mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Merge from rustc
This commit is contained in:
commit
8faa34e2ec
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
@ -154,9 +154,12 @@ jobs:
|
||||
|
||||
- name: checkout submodules
|
||||
run: src/ci/scripts/checkout-submodules.sh
|
||||
|
||||
- name: install MSYS2
|
||||
run: src/ci/scripts/install-msys2.sh
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
if: runner.environment == 'github-hosted'
|
||||
|
||||
- name: install MinGW
|
||||
run: src/ci/scripts/install-mingw.sh
|
||||
|
@ -4082,6 +4082,7 @@ dependencies = [
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_hir_pretty",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_macros",
|
||||
|
@ -970,7 +970,7 @@ fn univariant<
|
||||
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
|
||||
let mut max_repr_align = repr.align;
|
||||
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
|
||||
let optimize = !repr.inhibit_struct_field_reordering_opt();
|
||||
let optimize = !repr.inhibit_struct_field_reordering();
|
||||
if optimize && fields.len() > 1 {
|
||||
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
|
||||
let optimizing = &mut inverse_memory_index.raw[..end];
|
||||
@ -1007,13 +1007,15 @@ fn univariant<
|
||||
// Calculates a sort key to group fields by their alignment or possibly some
|
||||
// size-derived pseudo-alignment.
|
||||
let alignment_group_key = |layout: &F| {
|
||||
// The two branches here return values that cannot be meaningfully compared with
|
||||
// each other. However, we know that consistently for all executions of
|
||||
// `alignment_group_key`, one or the other branch will be taken, so this is okay.
|
||||
if let Some(pack) = pack {
|
||||
// Return the packed alignment in bytes.
|
||||
layout.align.abi.min(pack).bytes()
|
||||
} else {
|
||||
// Returns `log2(effective-align)`. This is ok since `pack` applies to all
|
||||
// fields equally. The calculation assumes that size is an integer multiple of
|
||||
// align, except for ZSTs.
|
||||
// Returns `log2(effective-align)`. The calculation assumes that size is an
|
||||
// integer multiple of align, except for ZSTs.
|
||||
let align = layout.align.abi.bytes();
|
||||
let size = layout.size.bytes();
|
||||
let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0);
|
||||
|
@ -137,23 +137,16 @@ impl ReprOptions {
|
||||
self.c() || self.int.is_some()
|
||||
}
|
||||
|
||||
/// Returns `true` if this `#[repr()]` should inhibit struct field reordering
|
||||
/// optimizations, such as with `repr(C)`, `repr(packed(1))`, or `repr(<int>)`.
|
||||
pub fn inhibit_struct_field_reordering_opt(&self) -> bool {
|
||||
if let Some(pack) = self.pack {
|
||||
if pack.bytes() == 1 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this `#[repr()]` guarantees a fixed field order,
|
||||
/// e.g. `repr(C)` or `repr(<int>)`.
|
||||
pub fn inhibit_struct_field_reordering(&self) -> bool {
|
||||
self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some()
|
||||
}
|
||||
|
||||
/// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
|
||||
/// was enabled for its declaration crate.
|
||||
pub fn can_randomize_type_layout(&self) -> bool {
|
||||
!self.inhibit_struct_field_reordering_opt()
|
||||
&& self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
|
||||
!self.inhibit_struct_field_reordering() && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
|
||||
}
|
||||
|
||||
/// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations.
|
||||
|
@ -1393,7 +1393,7 @@ pub enum ExprKind {
|
||||
/// An array (e.g, `[a, b, c, d]`).
|
||||
Array(ThinVec<P<Expr>>),
|
||||
/// Allow anonymous constants from an inline `const` block
|
||||
ConstBlock(AnonConst),
|
||||
ConstBlock(P<Expr>),
|
||||
/// A function call
|
||||
///
|
||||
/// The first field resolves to the function itself,
|
||||
|
@ -1411,7 +1411,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
match kind {
|
||||
ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis),
|
||||
ExprKind::ConstBlock(anon_const) => {
|
||||
vis.visit_anon_const(anon_const);
|
||||
vis.visit_expr(anon_const);
|
||||
}
|
||||
ExprKind::Repeat(expr, count) => {
|
||||
vis.visit_expr(expr);
|
||||
|
@ -852,10 +852,10 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(
|
||||
ctxt: AssocCtxt,
|
||||
) -> V::Result {
|
||||
let &Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = item;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_vis(vis));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(kind.walk(item, ctxt, visitor));
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
@ -951,7 +951,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
||||
ExprKind::Array(subexpressions) => {
|
||||
walk_list!(visitor, visit_expr, subexpressions);
|
||||
}
|
||||
ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_anon_const(anon_const)),
|
||||
ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_expr(anon_const)),
|
||||
ExprKind::Repeat(element, count) => {
|
||||
try_visit!(visitor.visit_expr(element));
|
||||
try_visit!(visitor.visit_anon_const(count));
|
||||
|
@ -75,12 +75,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let kind = match &e.kind {
|
||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
ExprKind::ConstBlock(c) => {
|
||||
let c = self.with_new_scopes(c.value.span, |this| hir::ConstBlock {
|
||||
def_id: this.local_def_id(c.id),
|
||||
hir_id: this.lower_node_id(c.id),
|
||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||
});
|
||||
hir::ExprKind::ConstBlock(c)
|
||||
self.has_inline_consts = true;
|
||||
hir::ExprKind::ConstBlock(self.lower_expr(c))
|
||||
}
|
||||
ExprKind::Repeat(expr, count) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
|
@ -236,14 +236,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, constant: &'hir ConstBlock) {
|
||||
self.insert(DUMMY_SP, constant.hir_id, Node::ConstBlock(constant));
|
||||
|
||||
self.with_parent(constant.hir_id, |this| {
|
||||
intravisit::walk_inline_const(this, constant);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
|
||||
self.insert(expr.span, expr.hir_id, Node::Expr(expr));
|
||||
|
||||
|
@ -96,6 +96,8 @@ struct LoweringContext<'a, 'hir> {
|
||||
|
||||
/// Bodies inside the owner being lowered.
|
||||
bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
|
||||
/// Whether there were inline consts that typeck will split out into bodies
|
||||
has_inline_consts: bool,
|
||||
/// Attributes inside the owner being lowered.
|
||||
attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
|
||||
/// Collect items that were created by lowering the current owner.
|
||||
@ -158,6 +160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
item_local_id_counter: hir::ItemLocalId::ZERO,
|
||||
node_id_to_local_id: Default::default(),
|
||||
trait_map: Default::default(),
|
||||
has_inline_consts: false,
|
||||
|
||||
// Lowering state.
|
||||
catch_scope: None,
|
||||
@ -567,6 +570,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
let current_attrs = std::mem::take(&mut self.attrs);
|
||||
let current_bodies = std::mem::take(&mut self.bodies);
|
||||
let current_has_inline_consts = std::mem::take(&mut self.has_inline_consts);
|
||||
let current_node_ids = std::mem::take(&mut self.node_id_to_local_id);
|
||||
let current_trait_map = std::mem::take(&mut self.trait_map);
|
||||
let current_owner =
|
||||
@ -593,6 +597,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
self.attrs = current_attrs;
|
||||
self.bodies = current_bodies;
|
||||
self.has_inline_consts = current_has_inline_consts;
|
||||
self.node_id_to_local_id = current_node_ids;
|
||||
self.trait_map = current_trait_map;
|
||||
self.current_hir_id_owner = current_owner;
|
||||
@ -629,6 +634,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let attrs = std::mem::take(&mut self.attrs);
|
||||
let mut bodies = std::mem::take(&mut self.bodies);
|
||||
let trait_map = std::mem::take(&mut self.trait_map);
|
||||
let has_inline_consts = std::mem::take(&mut self.has_inline_consts);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
for (id, attrs) in attrs.iter() {
|
||||
@ -646,7 +652,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.tcx.hash_owner_nodes(node, &bodies, &attrs);
|
||||
let num_nodes = self.item_local_id_counter.as_usize();
|
||||
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
|
||||
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
|
||||
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies, has_inline_consts };
|
||||
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash };
|
||||
|
||||
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
|
||||
|
@ -380,8 +380,9 @@ impl<'a> State<'a> {
|
||||
ast::ExprKind::Array(exprs) => {
|
||||
self.print_expr_vec(exprs);
|
||||
}
|
||||
ast::ExprKind::ConstBlock(anon_const) => {
|
||||
self.print_expr_anon_const(anon_const, attrs);
|
||||
ast::ExprKind::ConstBlock(expr) => {
|
||||
self.word_space("const");
|
||||
self.print_expr(expr, FixupContext::default());
|
||||
}
|
||||
ast::ExprKind::Repeat(element, count) => {
|
||||
self.print_expr_repeat(element, count);
|
||||
|
@ -593,6 +593,7 @@ pub(crate) fn codegen_drop<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
source_info: mir::SourceInfo,
|
||||
drop_place: CPlace<'tcx>,
|
||||
target: BasicBlock,
|
||||
) {
|
||||
let ty = drop_place.layout().ty;
|
||||
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
|
||||
@ -620,6 +621,12 @@ pub(crate) fn codegen_drop<'tcx>(
|
||||
let ptr = ptr.get_addr(fx);
|
||||
let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable);
|
||||
|
||||
let is_null = fx.bcx.ins().icmp_imm(IntCC::Equal, drop_fn, 0);
|
||||
let target_block = fx.get_block(target);
|
||||
let continued = fx.bcx.create_block();
|
||||
fx.bcx.ins().brif(is_null, target_block, &[], continued, &[]);
|
||||
fx.bcx.switch_to_block(continued);
|
||||
|
||||
// FIXME(eddyb) perhaps move some of this logic into
|
||||
// `Instance::resolve_drop_in_place`?
|
||||
let virtual_drop = Instance {
|
||||
@ -659,6 +666,12 @@ pub(crate) fn codegen_drop<'tcx>(
|
||||
let (data, vtable) = drop_place.to_cvalue(fx).dyn_star_force_data_on_stack(fx);
|
||||
let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable);
|
||||
|
||||
let is_null = fx.bcx.ins().icmp_imm(IntCC::Equal, drop_fn, 0);
|
||||
let target_block = fx.get_block(target);
|
||||
let continued = fx.bcx.create_block();
|
||||
fx.bcx.ins().brif(is_null, target_block, &[], continued, &[]);
|
||||
fx.bcx.switch_to_block(continued);
|
||||
|
||||
let virtual_drop = Instance {
|
||||
def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
|
||||
args: drop_instance.args,
|
||||
@ -697,4 +710,7 @@ pub(crate) fn codegen_drop<'tcx>(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let target_block = fx.get_block(target);
|
||||
fx.bcx.ins().jump(target_block, &[]);
|
||||
}
|
||||
|
@ -548,10 +548,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||
}
|
||||
TerminatorKind::Drop { place, target, unwind: _, replace: _ } => {
|
||||
let drop_place = codegen_place(fx, *place);
|
||||
crate::abi::codegen_drop(fx, source_info, drop_place);
|
||||
|
||||
let target_block = fx.get_block(*target);
|
||||
fx.bcx.ins().jump(target_block, &[]);
|
||||
crate::abi::codegen_drop(fx, source_info, drop_place, *target);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -619,22 +616,34 @@ fn codegen_stmt<'tcx>(
|
||||
Rvalue::UnaryOp(un_op, ref operand) => {
|
||||
let operand = codegen_operand(fx, operand);
|
||||
let layout = operand.layout();
|
||||
let val = operand.load_scalar(fx);
|
||||
let res = match un_op {
|
||||
UnOp::Not => match layout.ty.kind() {
|
||||
ty::Bool => {
|
||||
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
|
||||
CValue::by_val(res, layout)
|
||||
UnOp::Not => {
|
||||
let val = operand.load_scalar(fx);
|
||||
match layout.ty.kind() {
|
||||
ty::Bool => {
|
||||
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
|
||||
CValue::by_val(res, layout)
|
||||
}
|
||||
ty::Uint(_) | ty::Int(_) => {
|
||||
CValue::by_val(fx.bcx.ins().bnot(val), layout)
|
||||
}
|
||||
_ => unreachable!("un op Not for {:?}", layout.ty),
|
||||
}
|
||||
ty::Uint(_) | ty::Int(_) => {
|
||||
CValue::by_val(fx.bcx.ins().bnot(val), layout)
|
||||
}
|
||||
UnOp::Neg => {
|
||||
let val = operand.load_scalar(fx);
|
||||
match layout.ty.kind() {
|
||||
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
|
||||
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
|
||||
_ => unreachable!("un op Neg for {:?}", layout.ty),
|
||||
}
|
||||
_ => unreachable!("un op Not for {:?}", layout.ty),
|
||||
},
|
||||
UnOp::Neg => match layout.ty.kind() {
|
||||
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
|
||||
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
|
||||
_ => unreachable!("un op Neg for {:?}", layout.ty),
|
||||
}
|
||||
UnOp::PtrMetadata => match layout.abi {
|
||||
Abi::Scalar(_) => CValue::zst(dest_layout),
|
||||
Abi::ScalarPair(_, _) => {
|
||||
CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout)
|
||||
}
|
||||
_ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"),
|
||||
},
|
||||
};
|
||||
lval.write_cvalue(fx, res);
|
||||
|
@ -100,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>(
|
||||
assert!(layout.is_sized(), "unsized const value");
|
||||
|
||||
if layout.is_zst() {
|
||||
return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout);
|
||||
return CValue::zst(layout);
|
||||
}
|
||||
|
||||
match const_val {
|
||||
|
@ -95,6 +95,14 @@ impl<'tcx> CValue<'tcx> {
|
||||
CValue(CValueInner::ByValPair(value, extra), layout)
|
||||
}
|
||||
|
||||
/// Create an instance of a ZST
|
||||
///
|
||||
/// The is represented by a dangling pointer of suitable alignment.
|
||||
pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> {
|
||||
assert!(layout.is_zst());
|
||||
CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout)
|
||||
}
|
||||
|
||||
pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
|
||||
self.1
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ codegen_llvm_error_creating_import_library =
|
||||
codegen_llvm_error_writing_def_file =
|
||||
Error writing .DEF file: {$error}
|
||||
|
||||
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
|
||||
|
||||
codegen_llvm_from_llvm_diag = {$message}
|
||||
|
||||
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
|
||||
|
@ -254,3 +254,9 @@ pub struct MismatchedDataLayout<'a> {
|
||||
pub(crate) struct InvalidTargetFeaturePrefix<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_fixed_x18_invalid_arch)]
|
||||
pub(crate) struct FixedX18InvalidArch<'a> {
|
||||
pub arch: &'a str,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::errors::{
|
||||
InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable,
|
||||
FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable,
|
||||
UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||
};
|
||||
use crate::llvm;
|
||||
@ -615,6 +615,15 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
|
||||
.flatten();
|
||||
features.extend(feats);
|
||||
|
||||
// -Zfixed-x18
|
||||
if sess.opts.unstable_opts.fixed_x18 {
|
||||
if sess.target.arch != "aarch64" {
|
||||
sess.dcx().emit_fatal(FixedX18InvalidArch { arch: &sess.target.arch });
|
||||
} else {
|
||||
features.push("+reserve-x18".into());
|
||||
}
|
||||
}
|
||||
|
||||
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
|
||||
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
|
||||
features: f,
|
||||
|
@ -15,12 +15,13 @@ impl<'a, 'tcx> VirtualIndex {
|
||||
VirtualIndex(index as u64)
|
||||
}
|
||||
|
||||
pub fn get_fn<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
fn get_fn_inner<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
self,
|
||||
bx: &mut Bx,
|
||||
llvtable: Bx::Value,
|
||||
ty: Ty<'tcx>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
nonnull: bool,
|
||||
) -> Bx::Value {
|
||||
// Load the function pointer from the object.
|
||||
debug!("get_fn({llvtable:?}, {ty:?}, {self:?})");
|
||||
@ -41,13 +42,35 @@ impl<'a, 'tcx> VirtualIndex {
|
||||
} else {
|
||||
let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset));
|
||||
let ptr = bx.load(llty, gep, ptr_align);
|
||||
bx.nonnull_metadata(ptr);
|
||||
// VTable loads are invariant.
|
||||
bx.set_invariant_load(ptr);
|
||||
if nonnull {
|
||||
bx.nonnull_metadata(ptr);
|
||||
}
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_optional_fn<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
self,
|
||||
bx: &mut Bx,
|
||||
llvtable: Bx::Value,
|
||||
ty: Ty<'tcx>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
) -> Bx::Value {
|
||||
self.get_fn_inner(bx, llvtable, ty, fn_abi, false)
|
||||
}
|
||||
|
||||
pub fn get_fn<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
self,
|
||||
bx: &mut Bx,
|
||||
llvtable: Bx::Value,
|
||||
ty: Ty<'tcx>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
) -> Bx::Value {
|
||||
self.get_fn_inner(bx, llvtable, ty, fn_abi, true)
|
||||
}
|
||||
|
||||
pub fn get_usize<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
self,
|
||||
bx: &mut Bx,
|
||||
|
@ -500,6 +500,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
&mut self,
|
||||
helper: TerminatorCodegenHelper<'tcx>,
|
||||
bx: &mut Bx,
|
||||
source_info: &mir::SourceInfo,
|
||||
location: mir::Place<'tcx>,
|
||||
target: mir::BasicBlock,
|
||||
unwind: mir::UnwindAction,
|
||||
@ -523,90 +524,106 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
args1 = [place.val.llval];
|
||||
&args1[..]
|
||||
};
|
||||
let (drop_fn, fn_abi, drop_instance) =
|
||||
match ty.kind() {
|
||||
// FIXME(eddyb) perhaps move some of this logic into
|
||||
// `Instance::resolve_drop_in_place`?
|
||||
ty::Dynamic(_, _, ty::Dyn) => {
|
||||
// IN THIS ARM, WE HAVE:
|
||||
// ty = *mut (dyn Trait)
|
||||
// which is: exists<T> ( *mut T, Vtable<T: Trait> )
|
||||
// args[0] args[1]
|
||||
//
|
||||
// args = ( Data, Vtable )
|
||||
// |
|
||||
// v
|
||||
// /-------\
|
||||
// | ... |
|
||||
// \-------/
|
||||
//
|
||||
let virtual_drop = Instance {
|
||||
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function
|
||||
args: drop_fn.args,
|
||||
};
|
||||
debug!("ty = {:?}", ty);
|
||||
debug!("drop_fn = {:?}", drop_fn);
|
||||
debug!("args = {:?}", args);
|
||||
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||
let vtable = args[1];
|
||||
// Truncate vtable off of args list
|
||||
args = &args[..1];
|
||||
(
|
||||
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
|
||||
.get_fn(bx, vtable, ty, fn_abi),
|
||||
fn_abi,
|
||||
virtual_drop,
|
||||
)
|
||||
}
|
||||
ty::Dynamic(_, _, ty::DynStar) => {
|
||||
// IN THIS ARM, WE HAVE:
|
||||
// ty = *mut (dyn* Trait)
|
||||
// which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
|
||||
//
|
||||
// args = [ * ]
|
||||
// |
|
||||
// v
|
||||
// ( Data, Vtable )
|
||||
// |
|
||||
// v
|
||||
// /-------\
|
||||
// | ... |
|
||||
// \-------/
|
||||
//
|
||||
//
|
||||
// WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
|
||||
//
|
||||
// data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
|
||||
// vtable = (*args[0]).1 // loads the vtable out
|
||||
// (data, vtable) // an equivalent Rust `*mut dyn Trait`
|
||||
//
|
||||
// SO THEN WE CAN USE THE ABOVE CODE.
|
||||
let virtual_drop = Instance {
|
||||
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function
|
||||
args: drop_fn.args,
|
||||
};
|
||||
debug!("ty = {:?}", ty);
|
||||
debug!("drop_fn = {:?}", drop_fn);
|
||||
debug!("args = {:?}", args);
|
||||
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||
let meta_ptr = place.project_field(bx, 1);
|
||||
let meta = bx.load_operand(meta_ptr);
|
||||
// Truncate vtable off of args list
|
||||
args = &args[..1];
|
||||
debug!("args' = {:?}", args);
|
||||
(
|
||||
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
|
||||
.get_fn(bx, meta.immediate(), ty, fn_abi),
|
||||
fn_abi,
|
||||
virtual_drop,
|
||||
)
|
||||
}
|
||||
_ => (
|
||||
bx.get_fn_addr(drop_fn),
|
||||
bx.fn_abi_of_instance(drop_fn, ty::List::empty()),
|
||||
drop_fn,
|
||||
),
|
||||
};
|
||||
let (maybe_null, drop_fn, fn_abi, drop_instance) = match ty.kind() {
|
||||
// FIXME(eddyb) perhaps move some of this logic into
|
||||
// `Instance::resolve_drop_in_place`?
|
||||
ty::Dynamic(_, _, ty::Dyn) => {
|
||||
// IN THIS ARM, WE HAVE:
|
||||
// ty = *mut (dyn Trait)
|
||||
// which is: exists<T> ( *mut T, Vtable<T: Trait> )
|
||||
// args[0] args[1]
|
||||
//
|
||||
// args = ( Data, Vtable )
|
||||
// |
|
||||
// v
|
||||
// /-------\
|
||||
// | ... |
|
||||
// \-------/
|
||||
//
|
||||
let virtual_drop = Instance {
|
||||
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function
|
||||
args: drop_fn.args,
|
||||
};
|
||||
debug!("ty = {:?}", ty);
|
||||
debug!("drop_fn = {:?}", drop_fn);
|
||||
debug!("args = {:?}", args);
|
||||
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||
let vtable = args[1];
|
||||
// Truncate vtable off of args list
|
||||
args = &args[..1];
|
||||
(
|
||||
true,
|
||||
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
|
||||
.get_optional_fn(bx, vtable, ty, fn_abi),
|
||||
fn_abi,
|
||||
virtual_drop,
|
||||
)
|
||||
}
|
||||
ty::Dynamic(_, _, ty::DynStar) => {
|
||||
// IN THIS ARM, WE HAVE:
|
||||
// ty = *mut (dyn* Trait)
|
||||
// which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
|
||||
//
|
||||
// args = [ * ]
|
||||
// |
|
||||
// v
|
||||
// ( Data, Vtable )
|
||||
// |
|
||||
// v
|
||||
// /-------\
|
||||
// | ... |
|
||||
// \-------/
|
||||
//
|
||||
//
|
||||
// WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
|
||||
//
|
||||
// data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
|
||||
// vtable = (*args[0]).1 // loads the vtable out
|
||||
// (data, vtable) // an equivalent Rust `*mut dyn Trait`
|
||||
//
|
||||
// SO THEN WE CAN USE THE ABOVE CODE.
|
||||
let virtual_drop = Instance {
|
||||
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function
|
||||
args: drop_fn.args,
|
||||
};
|
||||
debug!("ty = {:?}", ty);
|
||||
debug!("drop_fn = {:?}", drop_fn);
|
||||
debug!("args = {:?}", args);
|
||||
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||
let meta_ptr = place.project_field(bx, 1);
|
||||
let meta = bx.load_operand(meta_ptr);
|
||||
// Truncate vtable off of args list
|
||||
args = &args[..1];
|
||||
debug!("args' = {:?}", args);
|
||||
(
|
||||
true,
|
||||
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
|
||||
.get_optional_fn(bx, meta.immediate(), ty, fn_abi),
|
||||
fn_abi,
|
||||
virtual_drop,
|
||||
)
|
||||
}
|
||||
_ => (
|
||||
false,
|
||||
bx.get_fn_addr(drop_fn),
|
||||
bx.fn_abi_of_instance(drop_fn, ty::List::empty()),
|
||||
drop_fn,
|
||||
),
|
||||
};
|
||||
|
||||
// We generate a null check for the drop_fn. This saves a bunch of relocations being
|
||||
// generated for no-op drops.
|
||||
if maybe_null {
|
||||
let is_not_null = bx.append_sibling_block("is_not_null");
|
||||
let llty = bx.fn_ptr_backend_type(fn_abi);
|
||||
let null = bx.const_null(llty);
|
||||
let non_null =
|
||||
bx.icmp(base::bin_op_to_icmp_predicate(mir::BinOp::Ne, false), drop_fn, null);
|
||||
bx.cond_br(non_null, is_not_null, helper.llbb_with_cleanup(self, target));
|
||||
bx.switch_to_block(is_not_null);
|
||||
self.set_debug_loc(bx, *source_info);
|
||||
}
|
||||
|
||||
helper.do_call(
|
||||
self,
|
||||
bx,
|
||||
@ -617,7 +634,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
unwind,
|
||||
&[],
|
||||
Some(drop_instance),
|
||||
mergeable_succ,
|
||||
!maybe_null && mergeable_succ,
|
||||
)
|
||||
}
|
||||
|
||||
@ -1346,9 +1363,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
MergingSucc::False
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => {
|
||||
self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ())
|
||||
}
|
||||
mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => self
|
||||
.codegen_drop_terminator(
|
||||
helper,
|
||||
bx,
|
||||
&terminator.source_info,
|
||||
place,
|
||||
target,
|
||||
unwind,
|
||||
mergeable_succ(),
|
||||
),
|
||||
|
||||
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self
|
||||
.codegen_assert_terminator(
|
||||
|
@ -565,6 +565,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
for elem in place_ref.projection.iter() {
|
||||
match elem {
|
||||
mir::ProjectionElem::Field(ref f, _) => {
|
||||
debug_assert!(
|
||||
!o.layout.ty.is_any_ptr(),
|
||||
"Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
|
||||
but tried to access field {f:?} of pointer {o:?}",
|
||||
);
|
||||
o = o.extract_field(bx, f.index());
|
||||
}
|
||||
mir::ProjectionElem::Index(_)
|
||||
|
@ -480,6 +480,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
cg_base = match *elem {
|
||||
mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
|
||||
mir::ProjectionElem::Field(ref field, _) => {
|
||||
debug_assert!(
|
||||
!cg_base.layout.ty.is_any_ptr(),
|
||||
"Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
|
||||
but tried to access field {field:?} of pointer {cg_base:?}",
|
||||
);
|
||||
cg_base.project_field(bx, field.index())
|
||||
}
|
||||
mir::ProjectionElem::OpaqueCast(ty) => {
|
||||
|
@ -623,19 +623,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
|
||||
mir::Rvalue::UnaryOp(op, ref operand) => {
|
||||
let operand = self.codegen_operand(bx, operand);
|
||||
let lloperand = operand.immediate();
|
||||
let is_float = operand.layout.ty.is_floating_point();
|
||||
let llval = match op {
|
||||
mir::UnOp::Not => bx.not(lloperand),
|
||||
let (val, layout) = match op {
|
||||
mir::UnOp::Not => {
|
||||
let llval = bx.not(operand.immediate());
|
||||
(OperandValue::Immediate(llval), operand.layout)
|
||||
}
|
||||
mir::UnOp::Neg => {
|
||||
if is_float {
|
||||
bx.fneg(lloperand)
|
||||
let llval = if is_float {
|
||||
bx.fneg(operand.immediate())
|
||||
} else {
|
||||
bx.neg(lloperand)
|
||||
bx.neg(operand.immediate())
|
||||
};
|
||||
(OperandValue::Immediate(llval), operand.layout)
|
||||
}
|
||||
mir::UnOp::PtrMetadata => {
|
||||
debug_assert!(operand.layout.ty.is_unsafe_ptr());
|
||||
let (_, meta) = operand.val.pointer_parts();
|
||||
assert_eq!(operand.layout.fields.count() > 1, meta.is_some());
|
||||
if let Some(meta) = meta {
|
||||
(OperandValue::Immediate(meta), operand.layout.field(self.cx, 1))
|
||||
} else {
|
||||
(OperandValue::ZeroSized, bx.cx().layout_of(bx.tcx().types.unit))
|
||||
}
|
||||
}
|
||||
};
|
||||
OperandRef { val: OperandValue::Immediate(llval), layout: operand.layout }
|
||||
debug_assert!(
|
||||
val.is_expected_variant_for_type(self.cx, layout),
|
||||
"Made wrong variant {val:?} for type {layout:?}",
|
||||
);
|
||||
OperandRef { val, layout }
|
||||
}
|
||||
|
||||
mir::Rvalue::Discriminant(ref place) => {
|
||||
@ -718,8 +735,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
let values = op.val.immediates_or_place().left_or_else(|p| {
|
||||
bug!("Field {field_idx:?} is {p:?} making {layout:?}");
|
||||
});
|
||||
inputs.extend(values);
|
||||
let scalars = self.value_kind(op.layout).scalars().unwrap();
|
||||
debug_assert_eq!(values.len(), scalars.len());
|
||||
inputs.extend(values);
|
||||
input_scalars.extend(scalars);
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn init_frame_extra(
|
||||
fn init_frame(
|
||||
_ecx: &mut InterpCx<'tcx, Self>,
|
||||
_frame: interpret::Frame<'tcx, Self::Provenance>,
|
||||
) -> interpret::InterpResult<'tcx, interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>>
|
||||
|
@ -38,7 +38,6 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
|
||||
match node {
|
||||
hir::Node::Ctor(_)
|
||||
| hir::Node::AnonConst(_)
|
||||
| hir::Node::ConstBlock(_)
|
||||
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => {
|
||||
hir::Constness::Const
|
||||
}
|
||||
@ -57,6 +56,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
|
||||
if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
|
||||
}
|
||||
hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness,
|
||||
hir::Node::Expr(e) if let hir::ExprKind::ConstBlock(_) = e.kind => hir::Constness::Const,
|
||||
_ => {
|
||||
if let Some(fn_kind) = node.fn_kind() {
|
||||
if fn_kind.constness() == hir::Constness::Const {
|
||||
|
@ -6,7 +6,6 @@ use std::ops::ControlFlow;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::fx::IndexEntry;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::LangItem;
|
||||
@ -392,18 +391,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> {
|
||||
instance: ty::InstanceDef<'tcx>,
|
||||
) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
|
||||
match instance {
|
||||
ty::InstanceDef::Item(def) => {
|
||||
if ecx.tcx.is_ctfe_mir_available(def) {
|
||||
Ok(ecx.tcx.mir_for_ctfe(def))
|
||||
} else if ecx.tcx.def_kind(def) == DefKind::AssocConst {
|
||||
ecx.tcx.dcx().bug("This is likely a const item that is missing from its impl");
|
||||
} else {
|
||||
// `find_mir_or_eval_fn` checks that this is a const fn before even calling us,
|
||||
// so this should be unreachable.
|
||||
let path = ecx.tcx.def_path_str(def);
|
||||
bug!("trying to call extern function `{path}` at compile-time");
|
||||
}
|
||||
}
|
||||
ty::InstanceDef::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)),
|
||||
_ => Ok(ecx.tcx.instance_mir(instance)),
|
||||
}
|
||||
}
|
||||
@ -655,7 +643,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn init_frame_extra(
|
||||
fn init_frame(
|
||||
ecx: &mut InterpCx<'tcx, Self>,
|
||||
frame: Frame<'tcx>,
|
||||
) -> InterpResult<'tcx, Frame<'tcx>> {
|
||||
|
@ -207,7 +207,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
assert!(cast_to.ty.is_unsafe_ptr());
|
||||
// Handle casting any ptr to raw ptr (might be a fat ptr).
|
||||
if cast_to.size == src.layout.size {
|
||||
// Thin or fat pointer that just hast the ptr kind of target type changed.
|
||||
// Thin or fat pointer that just has the ptr kind of target type changed.
|
||||
return Ok(ImmTy::from_immediate(**src, cast_to));
|
||||
} else {
|
||||
// Casting the metadata away from a fat ptr.
|
||||
|
@ -819,7 +819,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
tracing_span: SpanGuard::new(),
|
||||
extra: (),
|
||||
};
|
||||
let frame = M::init_frame_extra(self, pre_frame)?;
|
||||
let frame = M::init_frame(self, pre_frame)?;
|
||||
self.stack_mut().push(frame);
|
||||
|
||||
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
|
||||
|
@ -329,27 +329,41 @@ pub trait Machine<'tcx>: Sized {
|
||||
ptr: Pointer<Self::Provenance>,
|
||||
) -> Option<(AllocId, Size, Self::ProvenanceExtra)>;
|
||||
|
||||
/// Called to adjust allocations to the Provenance and AllocExtra of this machine.
|
||||
/// Called to adjust global allocations to the Provenance and AllocExtra of this machine.
|
||||
///
|
||||
/// If `alloc` contains pointers, then they are all pointing to globals.
|
||||
///
|
||||
/// The way we construct allocations is to always first construct it without extra and then add
|
||||
/// the extra. This keeps uniform code paths for handling both allocations created by CTFE for
|
||||
/// globals, and allocations created by Miri during evaluation.
|
||||
///
|
||||
/// `kind` is the kind of the allocation being adjusted; it can be `None` when
|
||||
/// it's a global and `GLOBAL_KIND` is `None`.
|
||||
///
|
||||
/// This should avoid copying if no work has to be done! If this returns an owned
|
||||
/// allocation (because a copy had to be done to adjust things), machine memory will
|
||||
/// cache the result. (This relies on `AllocMap::get_or` being able to add the
|
||||
/// owned allocation to the map even when the map is shared.)
|
||||
fn adjust_allocation<'b>(
|
||||
fn adjust_global_allocation<'b>(
|
||||
ecx: &InterpCx<'tcx, Self>,
|
||||
id: AllocId,
|
||||
alloc: Cow<'b, Allocation>,
|
||||
kind: Option<MemoryKind<Self::MemoryKind>>,
|
||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>;
|
||||
alloc: &'b Allocation,
|
||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
|
||||
{
|
||||
// The default implementation does a copy; CTFE machines have a more efficient implementation
|
||||
// based on their particular choice for `Provenance`, `AllocExtra`, and `Bytes`.
|
||||
let kind = Self::GLOBAL_KIND
|
||||
.expect("if GLOBAL_KIND is None, adjust_global_allocation must be overwritten");
|
||||
let alloc = alloc.adjust_from_tcx(&ecx.tcx, |ptr| ecx.global_root_pointer(ptr))?;
|
||||
let extra =
|
||||
Self::init_alloc_extra(ecx, id, MemoryKind::Machine(kind), alloc.size(), alloc.align)?;
|
||||
Ok(Cow::Owned(alloc.with_extra(extra)))
|
||||
}
|
||||
|
||||
/// Initialize the extra state of an allocation.
|
||||
///
|
||||
/// This is guaranteed to be called exactly once on all allocations that are accessed by the
|
||||
/// program.
|
||||
fn init_alloc_extra(
|
||||
ecx: &InterpCx<'tcx, Self>,
|
||||
id: AllocId,
|
||||
kind: MemoryKind<Self::MemoryKind>,
|
||||
size: Size,
|
||||
align: Align,
|
||||
) -> InterpResult<'tcx, Self::AllocExtra>;
|
||||
|
||||
/// Return a "root" pointer for the given allocation: the one that is used for direct
|
||||
/// accesses to this static/const/fn allocation, or the one returned from the heap allocator.
|
||||
@ -473,7 +487,7 @@ pub trait Machine<'tcx>: Sized {
|
||||
}
|
||||
|
||||
/// Called immediately before a new stack frame gets pushed.
|
||||
fn init_frame_extra(
|
||||
fn init_frame(
|
||||
ecx: &mut InterpCx<'tcx, Self>,
|
||||
frame: Frame<'tcx, Self::Provenance>,
|
||||
) -> InterpResult<'tcx, Frame<'tcx, Self::Provenance, Self::FrameExtra>>;
|
||||
@ -590,13 +604,23 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn adjust_allocation<'b>(
|
||||
fn adjust_global_allocation<'b>(
|
||||
_ecx: &InterpCx<$tcx, Self>,
|
||||
_id: AllocId,
|
||||
alloc: Cow<'b, Allocation>,
|
||||
_kind: Option<MemoryKind<Self::MemoryKind>>,
|
||||
alloc: &'b Allocation,
|
||||
) -> InterpResult<$tcx, Cow<'b, Allocation<Self::Provenance>>> {
|
||||
Ok(alloc)
|
||||
// Overwrite default implementation: no need to adjust anything.
|
||||
Ok(Cow::Borrowed(alloc))
|
||||
}
|
||||
|
||||
fn init_alloc_extra(
|
||||
_ecx: &InterpCx<$tcx, Self>,
|
||||
_id: AllocId,
|
||||
_kind: MemoryKind<Self::MemoryKind>,
|
||||
_size: Size,
|
||||
_align: Align,
|
||||
) -> InterpResult<$tcx, Self::AllocExtra> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extern_static_pointer(
|
||||
|
@ -239,7 +239,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
|
||||
pub fn allocate_raw_ptr(
|
||||
&mut self,
|
||||
alloc: Allocation,
|
||||
alloc: Allocation<M::Provenance, (), M::Bytes>,
|
||||
kind: MemoryKind<M::MemoryKind>,
|
||||
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
|
||||
let id = self.tcx.reserve_alloc_id();
|
||||
@ -248,8 +248,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
M::GLOBAL_KIND.map(MemoryKind::Machine),
|
||||
"dynamically allocating global memory"
|
||||
);
|
||||
let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
|
||||
self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
|
||||
// We have set things up so we don't need to call `adjust_from_tcx` here,
|
||||
// so we avoid copying the entire allocation contents.
|
||||
let extra = M::init_alloc_extra(self, id, kind, alloc.size(), alloc.align)?;
|
||||
let alloc = alloc.with_extra(extra);
|
||||
self.memory.alloc_map.insert(id, (kind, alloc));
|
||||
M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind))
|
||||
}
|
||||
|
||||
@ -583,11 +586,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
};
|
||||
M::before_access_global(self.tcx, &self.machine, id, alloc, def_id, is_write)?;
|
||||
// We got tcx memory. Let the machine initialize its "extra" stuff.
|
||||
M::adjust_allocation(
|
||||
M::adjust_global_allocation(
|
||||
self,
|
||||
id, // always use the ID we got as input, not the "hidden" one.
|
||||
Cow::Borrowed(alloc.inner()),
|
||||
M::GLOBAL_KIND.map(MemoryKind::Machine),
|
||||
alloc.inner(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::symbol::sym;
|
||||
use tracing::trace;
|
||||
|
||||
use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine};
|
||||
use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta};
|
||||
|
||||
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> {
|
||||
@ -415,11 +415,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
use rustc_middle::mir::UnOp::*;
|
||||
|
||||
let layout = val.layout;
|
||||
let val = val.to_scalar();
|
||||
trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty);
|
||||
|
||||
match layout.ty.kind() {
|
||||
ty::Bool => {
|
||||
let val = val.to_scalar();
|
||||
let val = val.to_bool()?;
|
||||
let res = match un_op {
|
||||
Not => !val,
|
||||
@ -428,6 +428,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
Ok(ImmTy::from_bool(res, *self.tcx))
|
||||
}
|
||||
ty::Float(fty) => {
|
||||
let val = val.to_scalar();
|
||||
// No NaN adjustment here, `-` is a bitwise operation!
|
||||
let res = match (un_op, fty) {
|
||||
(Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?),
|
||||
@ -436,8 +437,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
};
|
||||
Ok(ImmTy::from_scalar(res, layout))
|
||||
}
|
||||
_ => {
|
||||
assert!(layout.ty.is_integral());
|
||||
_ if layout.ty.is_integral() => {
|
||||
let val = val.to_scalar();
|
||||
let val = val.to_bits(layout.size)?;
|
||||
let res = match un_op {
|
||||
Not => self.truncate(!val, layout), // bitwise negation, then truncate
|
||||
@ -450,9 +451,28 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
// Truncate to target type.
|
||||
self.truncate(res, layout)
|
||||
}
|
||||
_ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op),
|
||||
};
|
||||
Ok(ImmTy::from_uint(res, layout))
|
||||
}
|
||||
ty::RawPtr(..) => {
|
||||
assert_eq!(un_op, PtrMetadata);
|
||||
let (_, meta) = val.to_scalar_and_meta();
|
||||
Ok(match meta {
|
||||
MemPlaceMeta::Meta(scalar) => {
|
||||
let ty = un_op.ty(*self.tcx, val.layout.ty);
|
||||
let layout = self.layout_of(ty)?;
|
||||
ImmTy::from_scalar(scalar, layout)
|
||||
}
|
||||
MemPlaceMeta::None => {
|
||||
let unit_layout = self.layout_of(self.tcx.types.unit)?;
|
||||
ImmTy::uninit(unit_layout)
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
bug!("Unexpected unary op argument {val:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -804,6 +804,39 @@ fn print_crate_info(
|
||||
println_info!("{cfg}");
|
||||
}
|
||||
}
|
||||
CheckCfg => {
|
||||
let mut check_cfgs: Vec<String> = Vec::with_capacity(410);
|
||||
|
||||
// INSTABILITY: We are sorting the output below.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
for (name, expected_values) in &sess.psess.check_config.expecteds {
|
||||
use crate::config::ExpectedValues;
|
||||
match expected_values {
|
||||
ExpectedValues::Any => check_cfgs.push(format!("{name}=any()")),
|
||||
ExpectedValues::Some(values) => {
|
||||
check_cfgs.extend(values.iter().map(|value| {
|
||||
if let Some(value) = value {
|
||||
format!("{name}=\"{value}\"")
|
||||
} else {
|
||||
name.to_string()
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check_cfgs.sort_unstable();
|
||||
if !sess.psess.check_config.exhaustive_names {
|
||||
if !sess.psess.check_config.exhaustive_values {
|
||||
println_info!("any()=any()");
|
||||
} else {
|
||||
println_info!("any()");
|
||||
}
|
||||
}
|
||||
for check_cfg in check_cfgs {
|
||||
println_info!("{check_cfg}");
|
||||
}
|
||||
}
|
||||
CallingConventions => {
|
||||
let mut calling_conventions = rustc_target::spec::abi::all_names();
|
||||
calling_conventions.sort_unstable();
|
||||
|
@ -876,6 +876,9 @@ pub struct OwnerNodes<'tcx> {
|
||||
pub nodes: IndexVec<ItemLocalId, ParentedNode<'tcx>>,
|
||||
/// Content of local bodies.
|
||||
pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>,
|
||||
/// Whether the body contains inline constants that are created for the query system during typeck
|
||||
/// of the body.
|
||||
pub has_inline_consts: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> OwnerNodes<'tcx> {
|
||||
@ -1592,14 +1595,6 @@ pub struct AnonConst {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// An inline constant expression `const { something }`.
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic)]
|
||||
pub struct ConstBlock {
|
||||
pub hir_id: HirId,
|
||||
pub def_id: LocalDefId,
|
||||
pub body: BodyId,
|
||||
}
|
||||
|
||||
/// An expression.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct Expr<'hir> {
|
||||
@ -1886,7 +1881,7 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum ExprKind<'hir> {
|
||||
/// Allow anonymous constants from an inline `const` block
|
||||
ConstBlock(ConstBlock),
|
||||
ConstBlock(&'hir Expr<'hir>),
|
||||
/// An array (e.g., `[a, b, c, d]`).
|
||||
Array(&'hir [Expr<'hir>]),
|
||||
/// A function call.
|
||||
@ -3609,7 +3604,6 @@ pub enum Node<'hir> {
|
||||
Variant(&'hir Variant<'hir>),
|
||||
Field(&'hir FieldDef<'hir>),
|
||||
AnonConst(&'hir AnonConst),
|
||||
ConstBlock(&'hir ConstBlock),
|
||||
Expr(&'hir Expr<'hir>),
|
||||
ExprField(&'hir ExprField<'hir>),
|
||||
Stmt(&'hir Stmt<'hir>),
|
||||
@ -3670,7 +3664,6 @@ impl<'hir> Node<'hir> {
|
||||
Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident),
|
||||
Node::Param(..)
|
||||
| Node::AnonConst(..)
|
||||
| Node::ConstBlock(..)
|
||||
| Node::Expr(..)
|
||||
| Node::Stmt(..)
|
||||
| Node::Block(..)
|
||||
@ -3768,7 +3761,6 @@ impl<'hir> Node<'hir> {
|
||||
}
|
||||
|
||||
Node::AnonConst(constant) => Some((constant.def_id, constant.body)),
|
||||
Node::ConstBlock(constant) => Some((constant.def_id, constant.body)),
|
||||
|
||||
_ => None,
|
||||
}
|
||||
@ -3837,7 +3829,6 @@ impl<'hir> Node<'hir> {
|
||||
expect_variant, &'hir Variant<'hir>, Node::Variant(n), n;
|
||||
expect_field, &'hir FieldDef<'hir>, Node::Field(n), n;
|
||||
expect_anon_const, &'hir AnonConst, Node::AnonConst(n), n;
|
||||
expect_inline_const, &'hir ConstBlock, Node::ConstBlock(n), n;
|
||||
expect_expr, &'hir Expr<'hir>, Node::Expr(n), n;
|
||||
expect_expr_field, &'hir ExprField<'hir>, Node::ExprField(n), n;
|
||||
expect_stmt, &'hir Stmt<'hir>, Node::Stmt(n), n;
|
||||
|
@ -344,9 +344,6 @@ pub trait Visitor<'v>: Sized {
|
||||
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
|
||||
walk_anon_const(self, c)
|
||||
}
|
||||
fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result {
|
||||
walk_inline_const(self, c)
|
||||
}
|
||||
fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result {
|
||||
walk_expr(self, ex)
|
||||
}
|
||||
@ -716,14 +713,6 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo
|
||||
visitor.visit_nested_body(constant.body)
|
||||
}
|
||||
|
||||
pub fn walk_inline_const<'v, V: Visitor<'v>>(
|
||||
visitor: &mut V,
|
||||
constant: &'v ConstBlock,
|
||||
) -> V::Result {
|
||||
try_visit!(visitor.visit_id(constant.hir_id));
|
||||
visitor.visit_nested_body(constant.body)
|
||||
}
|
||||
|
||||
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(expression.hir_id));
|
||||
match expression.kind {
|
||||
@ -731,7 +720,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
||||
walk_list!(visitor, visit_expr, subexpressions);
|
||||
}
|
||||
ExprKind::ConstBlock(ref const_block) => {
|
||||
try_visit!(visitor.visit_inline_const(const_block))
|
||||
try_visit!(visitor.visit_expr(const_block))
|
||||
}
|
||||
ExprKind::Repeat(ref element, ref count) => {
|
||||
try_visit!(visitor.visit_expr(element));
|
||||
|
@ -228,13 +228,18 @@ language_item_table! {
|
||||
AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
AsyncFnKindHelper, sym::async_fn_kind_helper,async_fn_kind_helper, Target::Trait, GenericRequirement::Exact(1);
|
||||
AsyncFnOnceOutput, sym::async_fn_once_output, async_fn_once_output, Target::AssocTy, GenericRequirement::Exact(1);
|
||||
CallOnceFuture, sym::call_once_future, call_once_future, Target::AssocTy, GenericRequirement::Exact(1);
|
||||
CallRefFuture, sym::call_ref_future, call_ref_future, Target::AssocTy, GenericRequirement::Exact(2);
|
||||
AsyncFnKindHelper, sym::async_fn_kind_helper, async_fn_kind_helper, Target::Trait, GenericRequirement::Exact(1);
|
||||
AsyncFnKindUpvars, sym::async_fn_kind_upvars, async_fn_kind_upvars, Target::AssocTy, GenericRequirement::Exact(5);
|
||||
|
||||
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
|
||||
|
||||
Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
FusedIterator, sym::fused_iterator, fused_iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
FutureOutput, sym::future_output, future_output, Target::AssocTy, GenericRequirement::Exact(0);
|
||||
AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
||||
CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None;
|
||||
|
@ -93,7 +93,8 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'
|
||||
// `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing
|
||||
// the body satisfies the condition of two nodes being different have different
|
||||
// `hash_stable` results.
|
||||
let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _ } = *self;
|
||||
let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _, has_inline_consts: _ } =
|
||||
*self;
|
||||
opt_hash_including_bodies.unwrap().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
@ -130,6 +130,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
|
||||
| sym::is_val_statically_known
|
||||
| sym::ptr_mask
|
||||
| sym::aggregate_raw_ptr
|
||||
| sym::ptr_metadata
|
||||
| sym::ub_checks
|
||||
| sym::fadd_algebraic
|
||||
| sym::fsub_algebraic
|
||||
@ -576,6 +577,7 @@ pub fn check_intrinsic_type(
|
||||
// This type check is not particularly useful, but the `where` bounds
|
||||
// on the definition in `core` do the heavy lifting for checking it.
|
||||
sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)),
|
||||
sym::ptr_metadata => (2, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)),
|
||||
|
||||
sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool),
|
||||
|
||||
|
@ -407,11 +407,14 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
||||
match expr.kind {
|
||||
// Manually recurse over closures and inline consts, because they are the only
|
||||
// case of nested bodies that share the parent environment.
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. })
|
||||
| hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => {
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||
let body = visitor.tcx.hir().body(body);
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(expr) => visitor.enter_body(expr.hir_id, |this| {
|
||||
this.cx.var_parent = None;
|
||||
resolve_local(this, None, Some(expr));
|
||||
}),
|
||||
hir::ExprKind::AssignOp(_, left_expr, right_expr) => {
|
||||
debug!(
|
||||
"resolve_expr - enabling pessimistic_yield, was previously {}",
|
||||
@ -782,6 +785,32 @@ impl<'tcx> RegionResolutionVisitor<'tcx> {
|
||||
}
|
||||
self.enter_scope(Scope { id, data: ScopeData::Node });
|
||||
}
|
||||
|
||||
fn enter_body(&mut self, hir_id: hir::HirId, f: impl FnOnce(&mut Self)) {
|
||||
// Save all state that is specific to the outer function
|
||||
// body. These will be restored once down below, once we've
|
||||
// visited the body.
|
||||
let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0);
|
||||
let outer_cx = self.cx;
|
||||
let outer_ts = mem::take(&mut self.terminating_scopes);
|
||||
// The 'pessimistic yield' flag is set to true when we are
|
||||
// processing a `+=` statement and have to make pessimistic
|
||||
// control flow assumptions. This doesn't apply to nested
|
||||
// bodies within the `+=` statements. See #69307.
|
||||
let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false);
|
||||
self.terminating_scopes.insert(hir_id.local_id);
|
||||
|
||||
self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::CallSite });
|
||||
self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::Arguments });
|
||||
|
||||
f(self);
|
||||
|
||||
// Restore context we had at the start.
|
||||
self.expr_and_pat_count = outer_ec;
|
||||
self.cx = outer_cx;
|
||||
self.terminating_scopes = outer_ts;
|
||||
self.pessimistic_yield = outer_pessimistic_yield;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
||||
@ -801,60 +830,40 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
||||
self.cx.parent
|
||||
);
|
||||
|
||||
// Save all state that is specific to the outer function
|
||||
// body. These will be restored once down below, once we've
|
||||
// visited the body.
|
||||
let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0);
|
||||
let outer_cx = self.cx;
|
||||
let outer_ts = mem::take(&mut self.terminating_scopes);
|
||||
// The 'pessimistic yield' flag is set to true when we are
|
||||
// processing a `+=` statement and have to make pessimistic
|
||||
// control flow assumptions. This doesn't apply to nested
|
||||
// bodies within the `+=` statements. See #69307.
|
||||
let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false);
|
||||
self.terminating_scopes.insert(body.value.hir_id.local_id);
|
||||
self.enter_body(body.value.hir_id, |this| {
|
||||
if this.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() {
|
||||
// The arguments and `self` are parented to the fn.
|
||||
this.cx.var_parent = this.cx.parent.take();
|
||||
for param in body.params {
|
||||
this.visit_pat(param.pat);
|
||||
}
|
||||
|
||||
self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::CallSite });
|
||||
self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::Arguments });
|
||||
|
||||
// The arguments and `self` are parented to the fn.
|
||||
self.cx.var_parent = self.cx.parent.take();
|
||||
for param in body.params {
|
||||
self.visit_pat(param.pat);
|
||||
}
|
||||
|
||||
// The body of the every fn is a root scope.
|
||||
self.cx.parent = self.cx.var_parent;
|
||||
if self.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() {
|
||||
self.visit_expr(body.value)
|
||||
} else {
|
||||
// Only functions have an outer terminating (drop) scope, while
|
||||
// temporaries in constant initializers may be 'static, but only
|
||||
// according to rvalue lifetime semantics, using the same
|
||||
// syntactical rules used for let initializers.
|
||||
//
|
||||
// e.g., in `let x = &f();`, the temporary holding the result from
|
||||
// the `f()` call lives for the entirety of the surrounding block.
|
||||
//
|
||||
// Similarly, `const X: ... = &f();` would have the result of `f()`
|
||||
// live for `'static`, implying (if Drop restrictions on constants
|
||||
// ever get lifted) that the value *could* have a destructor, but
|
||||
// it'd get leaked instead of the destructor running during the
|
||||
// evaluation of `X` (if at all allowed by CTFE).
|
||||
//
|
||||
// However, `const Y: ... = g(&f());`, like `let y = g(&f());`,
|
||||
// would *not* let the `f()` temporary escape into an outer scope
|
||||
// (i.e., `'static`), which means that after `g` returns, it drops,
|
||||
// and all the associated destruction scope rules apply.
|
||||
self.cx.var_parent = None;
|
||||
resolve_local(self, None, Some(body.value));
|
||||
}
|
||||
|
||||
// Restore context we had at the start.
|
||||
self.expr_and_pat_count = outer_ec;
|
||||
self.cx = outer_cx;
|
||||
self.terminating_scopes = outer_ts;
|
||||
self.pessimistic_yield = outer_pessimistic_yield;
|
||||
// The body of the every fn is a root scope.
|
||||
this.cx.parent = this.cx.var_parent;
|
||||
this.visit_expr(body.value)
|
||||
} else {
|
||||
// Only functions have an outer terminating (drop) scope, while
|
||||
// temporaries in constant initializers may be 'static, but only
|
||||
// according to rvalue lifetime semantics, using the same
|
||||
// syntactical rules used for let initializers.
|
||||
//
|
||||
// e.g., in `let x = &f();`, the temporary holding the result from
|
||||
// the `f()` call lives for the entirety of the surrounding block.
|
||||
//
|
||||
// Similarly, `const X: ... = &f();` would have the result of `f()`
|
||||
// live for `'static`, implying (if Drop restrictions on constants
|
||||
// ever get lifted) that the value *could* have a destructor, but
|
||||
// it'd get leaked instead of the destructor running during the
|
||||
// evaluation of `X` (if at all allowed by CTFE).
|
||||
//
|
||||
// However, `const Y: ... = g(&f());`, like `let y = g(&f());`,
|
||||
// would *not* let the `f()` temporary escape into an outer scope
|
||||
// (i.e., `'static`), which means that after `g` returns, it drops,
|
||||
// and all the associated destruction scope rules apply.
|
||||
this.cx.var_parent = None;
|
||||
resolve_local(this, None, Some(body.value));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_arm(&mut self, a: &'tcx Arm<'tcx>) {
|
||||
|
@ -1478,7 +1478,7 @@ pub fn suggest_impl_trait<'tcx>(
|
||||
),
|
||||
(
|
||||
infcx.tcx.lang_items().future_trait(),
|
||||
infcx.tcx.get_diagnostic_item(sym::FutureOutput),
|
||||
infcx.tcx.lang_items().future_output(),
|
||||
format_as_assoc,
|
||||
),
|
||||
(
|
||||
|
@ -177,10 +177,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
}
|
||||
}
|
||||
}
|
||||
Node::ConstBlock(_)
|
||||
| Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
|
||||
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
|
||||
}
|
||||
Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure { .. } | hir::ExprKind::ConstBlock { .. },
|
||||
..
|
||||
}) => Some(tcx.typeck_root_def_id(def_id.to_def_id())),
|
||||
Node::Item(item) => match item.kind {
|
||||
ItemKind::OpaqueTy(&hir::OpaqueTy {
|
||||
origin:
|
||||
@ -415,7 +415,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
}
|
||||
|
||||
// provide junk type parameter defs for const blocks.
|
||||
if let Node::ConstBlock(_) = node {
|
||||
if let Node::Expr(Expr { kind: ExprKind::ConstBlock(..), .. }) = node {
|
||||
own_params.push(ty::GenericParamDef {
|
||||
index: next_index(),
|
||||
name: Symbol::intern("<const_ty>"),
|
||||
|
@ -484,8 +484,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
|
||||
}
|
||||
|
||||
Node::AnonConst(_) => anon_const_type_of(tcx, def_id),
|
||||
|
||||
Node::ConstBlock(_) => {
|
||||
Node::Expr(&Expr { kind: ExprKind::ConstBlock(..), .. }) => {
|
||||
let args = ty::GenericArgs::identity_for_item(tcx, def_id.to_def_id());
|
||||
args.as_inline_const().ty()
|
||||
}
|
||||
|
@ -190,10 +190,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
||||
}
|
||||
});
|
||||
|
||||
// Freeze definitions as we don't add new ones at this point. This improves performance by
|
||||
// allowing lock-free access to them.
|
||||
tcx.untracked().definitions.freeze();
|
||||
|
||||
// FIXME: Remove this when we implement creating `DefId`s
|
||||
// for anon constants during their parents' typeck.
|
||||
// Typeck all body owners in parallel will produce queries
|
||||
@ -205,6 +201,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
||||
}
|
||||
});
|
||||
|
||||
// Freeze definitions as we don't add new ones at this point. This improves performance by
|
||||
// allowing lock-free access to them.
|
||||
tcx.untracked().definitions.freeze();
|
||||
|
||||
tcx.ensure().check_unused_traits(());
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,6 @@ impl<'a> State<'a> {
|
||||
Node::ImplItem(a) => self.print_impl_item(a),
|
||||
Node::Variant(a) => self.print_variant(a),
|
||||
Node::AnonConst(a) => self.print_anon_const(a),
|
||||
Node::ConstBlock(a) => self.print_inline_const(a),
|
||||
Node::Expr(a) => self.print_expr(a),
|
||||
Node::ExprField(a) => self.print_expr_field(a),
|
||||
Node::Stmt(a) => self.print_stmt(a),
|
||||
@ -1049,10 +1048,10 @@ impl<'a> State<'a> {
|
||||
self.end()
|
||||
}
|
||||
|
||||
fn print_inline_const(&mut self, constant: &hir::ConstBlock) {
|
||||
fn print_inline_const(&mut self, constant: &hir::Expr<'_>) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.word_space("const");
|
||||
self.ann.nested(self, Nested::Body(constant.body));
|
||||
self.print_expr(constant);
|
||||
self.end()
|
||||
}
|
||||
|
||||
|
@ -1158,7 +1158,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig));
|
||||
let sig = self
|
||||
.at(cause, self.param_env)
|
||||
.trace(prev_ty, new_ty)
|
||||
.lub(DefineOpaqueTypes::Yes, a_sig, b_sig)
|
||||
.map(|ok| self.register_infer_ok_obligations(ok))?;
|
||||
|
||||
|
@ -32,7 +32,6 @@ use rustc_errors::{
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, HirId, QPath};
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
|
||||
@ -336,7 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
|
||||
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
|
||||
ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected),
|
||||
ExprKind::ConstBlock(ref block) => self.check_expr_with_expectation(block, expected),
|
||||
ExprKind::Repeat(element, ref count) => {
|
||||
self.check_expr_repeat(element, count, expected, expr)
|
||||
}
|
||||
@ -1460,24 +1459,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr_const_block(
|
||||
&self,
|
||||
block: &'tcx hir::ConstBlock,
|
||||
expected: Expectation<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let body = self.tcx.hir().body(block.body);
|
||||
|
||||
// Create a new function context.
|
||||
let def_id = block.def_id;
|
||||
let fcx = FnCtxt::new(self, self.param_env, def_id);
|
||||
crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
|
||||
|
||||
let ty = fcx.check_expr_with_expectation(body.value, expected);
|
||||
fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::ConstSized);
|
||||
fcx.write_ty(block.hir_id, ty);
|
||||
ty
|
||||
}
|
||||
|
||||
fn check_expr_repeat(
|
||||
&self,
|
||||
element: &'tcx hir::Expr<'tcx>,
|
||||
|
@ -1055,6 +1055,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
.take_while(|(_, node)| {
|
||||
// look at parents until we find the first body owner
|
||||
node.body_id().is_none()
|
||||
&& !matches!(
|
||||
node,
|
||||
Node::Expr(Expr { kind: ExprKind::ConstBlock { .. }, .. })
|
||||
)
|
||||
})
|
||||
.any(|(parent_id, _)| self.is_loop(parent_id));
|
||||
|
||||
|
@ -149,10 +149,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
|
||||
self.visit_body(body);
|
||||
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(anon_const) => {
|
||||
let body = self.fcx.tcx.hir().body(anon_const.body);
|
||||
self.visit_body(body);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
// generic parameters.
|
||||
|
||||
use crate::FnCtxt;
|
||||
use hir::def::DefKind;
|
||||
use rustc_data_structures::unord::ExtendUnord;
|
||||
use rustc_errors::{ErrorGuaranteed, StashKey};
|
||||
use rustc_hir as hir;
|
||||
@ -16,7 +17,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::TypeSuperFoldable;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::solve;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
@ -295,11 +296,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||
hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => {
|
||||
self.visit_field_id(e.hir_id);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(anon_const) => {
|
||||
self.visit_node_id(e.span, anon_const.hir_id);
|
||||
|
||||
let body = self.tcx().hir().body(anon_const.body);
|
||||
self.visit_body(body);
|
||||
hir::ExprKind::ConstBlock(_) => {
|
||||
let feed = self.tcx().create_def(self.fcx.body_id, kw::Empty, DefKind::InlineConst);
|
||||
feed.def_span(e.span);
|
||||
feed.local_def_id_to_hir_id(e.hir_id);
|
||||
self.typeck_results.inline_consts.insert(e.hir_id.local_id, feed.def_id());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -48,11 +48,6 @@ pub struct At<'a, 'tcx> {
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
pub struct Trace<'a, 'tcx> {
|
||||
at: At<'a, 'tcx>,
|
||||
trace: TypeTrace<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
#[inline]
|
||||
pub fn at<'a>(
|
||||
@ -109,9 +104,6 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
/// call like `foo(x)`, where `foo: fn(i32)`, you might have
|
||||
/// `sup(i32, x)`, since the "expected" type is the type that
|
||||
/// appears in the signature.
|
||||
///
|
||||
/// See [`At::trace`] and [`Trace::sub`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
pub fn sup<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
@ -121,13 +113,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.trace(expected, actual).sup(define_opaque_types, expected, actual)
|
||||
let mut fields = CombineFields::new(
|
||||
self.infcx,
|
||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||
self.param_env,
|
||||
define_opaque_types,
|
||||
);
|
||||
fields
|
||||
.sup()
|
||||
.relate(expected, actual)
|
||||
.map(|_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
/// Makes `expected <: actual`.
|
||||
///
|
||||
/// See [`At::trace`] and [`Trace::sub`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
pub fn sub<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
@ -137,13 +135,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.trace(expected, actual).sub(define_opaque_types, expected, actual)
|
||||
let mut fields = CombineFields::new(
|
||||
self.infcx,
|
||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||
self.param_env,
|
||||
define_opaque_types,
|
||||
);
|
||||
fields
|
||||
.sub()
|
||||
.relate(expected, actual)
|
||||
.map(|_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
/// Makes `expected <: actual`.
|
||||
///
|
||||
/// See [`At::trace`] and [`Trace::eq`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
/// Makes `expected == actual`.
|
||||
pub fn eq<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
@ -153,7 +157,40 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.trace(expected, actual).eq(define_opaque_types, expected, actual)
|
||||
let mut fields = CombineFields::new(
|
||||
self.infcx,
|
||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||
self.param_env,
|
||||
define_opaque_types,
|
||||
);
|
||||
fields
|
||||
.equate(StructurallyRelateAliases::No)
|
||||
.relate(expected, actual)
|
||||
.map(|_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
/// Equates `expected` and `found` while structurally relating aliases.
|
||||
/// This should only be used inside of the next generation trait solver
|
||||
/// when relating rigid aliases.
|
||||
pub fn eq_structurally_relating_aliases<T>(
|
||||
self,
|
||||
expected: T,
|
||||
actual: T,
|
||||
) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
assert!(self.infcx.next_trait_solver());
|
||||
let mut fields = CombineFields::new(
|
||||
self.infcx,
|
||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||
self.param_env,
|
||||
DefineOpaqueTypes::Yes,
|
||||
);
|
||||
fields
|
||||
.equate(StructurallyRelateAliases::Yes)
|
||||
.relate(expected, actual)
|
||||
.map(|_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
pub fn relate<T>(
|
||||
@ -185,9 +222,6 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
/// this can result in an error (e.g., if asked to compute LUB of
|
||||
/// u32 and i32), it is meaningful to call one of them the
|
||||
/// "expected type".
|
||||
///
|
||||
/// See [`At::trace`] and [`Trace::lub`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
pub fn lub<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
@ -197,15 +231,21 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.trace(expected, actual).lub(define_opaque_types, expected, actual)
|
||||
let mut fields = CombineFields::new(
|
||||
self.infcx,
|
||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||
self.param_env,
|
||||
define_opaque_types,
|
||||
);
|
||||
fields
|
||||
.lub()
|
||||
.relate(expected, actual)
|
||||
.map(|value| InferOk { value, obligations: fields.obligations })
|
||||
}
|
||||
|
||||
/// Computes the greatest-lower-bound, or mutual subtype, of two
|
||||
/// values. As with `lub` order doesn't matter, except for error
|
||||
/// cases.
|
||||
///
|
||||
/// See [`At::trace`] and [`Trace::glb`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
pub fn glb<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
@ -215,105 +255,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.trace(expected, actual).glb(define_opaque_types, expected, actual)
|
||||
}
|
||||
|
||||
/// Sets the "trace" values that will be used for
|
||||
/// error-reporting, but doesn't actually perform any operation
|
||||
/// yet (this is useful when you want to set the trace using
|
||||
/// distinct values from those you wish to operate upon).
|
||||
pub fn trace<T>(self, expected: T, actual: T) -> Trace<'a, 'tcx>
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
let trace = ToTrace::to_trace(self.cause, true, expected, actual);
|
||||
Trace { at: self, trace }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Trace<'a, 'tcx> {
|
||||
/// Makes `a <: b`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
fields
|
||||
.sub()
|
||||
.relate(a, b)
|
||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
/// Makes `a :> b`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn sup<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
fields
|
||||
.sup()
|
||||
.relate(a, b)
|
||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
/// Makes `a == b`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
fields
|
||||
.equate(StructurallyRelateAliases::No)
|
||||
.relate(a, b)
|
||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
/// Equates `a` and `b` while structurally relating aliases. This should only
|
||||
/// be used inside of the next generation trait solver when relating rigid aliases.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn eq_structurally_relating_aliases<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace } = self;
|
||||
debug_assert!(at.infcx.next_trait_solver());
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::Yes);
|
||||
fields
|
||||
.equate(StructurallyRelateAliases::Yes)
|
||||
.relate(a, b)
|
||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn lub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
fields
|
||||
.lub()
|
||||
.relate(a, b)
|
||||
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn glb<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
let mut fields = CombineFields::new(
|
||||
self.infcx,
|
||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
||||
self.param_env,
|
||||
define_opaque_types,
|
||||
);
|
||||
fields
|
||||
.glb()
|
||||
.relate(a, b)
|
||||
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
.relate(expected, actual)
|
||||
.map(|value| InferOk { value, obligations: fields.obligations })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2102,10 +2102,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
// If a string was expected and the found expression is a character literal,
|
||||
// perhaps the user meant to write `"s"` to specify a string literal.
|
||||
(ty::Ref(_, r, _), ty::Char) if r.is_str() => {
|
||||
suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral {
|
||||
start: span.with_hi(span.lo() + BytePos(1)),
|
||||
end: span.with_lo(span.hi() - BytePos(1)),
|
||||
})
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
&& code.starts_with("'")
|
||||
&& code.ends_with("'")
|
||||
{
|
||||
suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral {
|
||||
start: span.with_hi(span.lo() + BytePos(1)),
|
||||
end: span.with_lo(span.hi() - BytePos(1)),
|
||||
});
|
||||
}
|
||||
}
|
||||
// For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
|
||||
// we try to suggest to add the missing `let` for `if let Some(..) = expr`
|
||||
|
@ -836,21 +836,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn combine_fields<'a>(
|
||||
&'a self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
) -> CombineFields<'a, 'tcx> {
|
||||
CombineFields {
|
||||
infcx: self,
|
||||
trace,
|
||||
param_env,
|
||||
obligations: PredicateObligations::new(),
|
||||
define_opaque_types,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool
|
||||
where
|
||||
T: at::ToTrace<'tcx>,
|
||||
|
@ -42,6 +42,17 @@ pub struct CombineFields<'infcx, 'tcx> {
|
||||
pub define_opaque_types: DefineOpaqueTypes,
|
||||
}
|
||||
|
||||
impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||
pub fn new(
|
||||
infcx: &'infcx InferCtxt<'tcx>,
|
||||
trace: TypeTrace<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
) -> Self {
|
||||
Self { infcx, trace, param_env, define_opaque_types, obligations: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
pub fn super_combine_tys<R>(
|
||||
&self,
|
||||
|
@ -773,6 +773,7 @@ fn test_unstable_options_tracking_hash() {
|
||||
tracked!(emit_thin_lto, false);
|
||||
tracked!(export_executable_symbols, true);
|
||||
tracked!(fewer_names, Some(true));
|
||||
tracked!(fixed_x18, true);
|
||||
tracked!(flatten_format_args, false);
|
||||
tracked!(force_unstable_if_unmarked, true);
|
||||
tracked!(fuel, Some(("abc".to_string(), 99)));
|
||||
|
@ -13,6 +13,7 @@ rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_infer = { path = "../rustc_infer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
|
@ -232,11 +232,9 @@ lint_drop_trait_constraints =
|
||||
|
||||
lint_dropping_copy_types = calls to `std::mem::drop` with a value that implements `Copy` does nothing
|
||||
.label = argument has type `{$arg_ty}`
|
||||
.note = use `let _ = ...` to ignore the expression or result
|
||||
|
||||
lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing
|
||||
.label = argument has type `{$arg_ty}`
|
||||
.note = use `let _ = ...` to ignore the expression or result
|
||||
|
||||
lint_duplicate_macro_attribute =
|
||||
duplicated attribute
|
||||
@ -271,10 +269,9 @@ lint_for_loops_over_fallibles =
|
||||
|
||||
lint_forgetting_copy_types = calls to `std::mem::forget` with a value that implements `Copy` does nothing
|
||||
.label = argument has type `{$arg_ty}`
|
||||
.note = use `let _ = ...` to ignore the expression or result
|
||||
|
||||
lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing
|
||||
.label = argument has type `{$arg_ty}`
|
||||
.note = use `let _ = ...` to ignore the expression or result
|
||||
|
||||
lint_hidden_glob_reexport = private item shadows public glob re-export
|
||||
.note_glob_reexport = the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here
|
||||
@ -542,17 +539,21 @@ lint_non_local_definitions_cargo_update = the {$macro_kind} `{$macro_name}` may
|
||||
|
||||
lint_non_local_definitions_deprecation = this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
lint_non_local_definitions_impl = non-local `impl` definition, they should be avoided as they go against expectation
|
||||
.help =
|
||||
move this `impl` block outside the of the current {$body_kind_descr} {$depth ->
|
||||
[one] `{$body_name}`
|
||||
*[other] `{$body_name}` and up {$depth} bodies
|
||||
}
|
||||
.non_local = an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl`
|
||||
.exception = one exception to the rule are anon-const (`const _: () = {"{"} ... {"}"}`) at top-level module and anon-const at the same nesting as the trait or type
|
||||
lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks should be written at the same level as their item
|
||||
.remove_help = remove `{$may_remove_part}` to make the `impl` local
|
||||
.without_trait = methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl`
|
||||
.with_trait = an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
|
||||
.bounds = `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type
|
||||
.exception = items in an anonymous const item (`const _: () = {"{"} ... {"}"}`) are treated as in the same scope as the anonymous const's declaration
|
||||
.const_anon = use a const-anon item to suppress this lint
|
||||
|
||||
lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, they should be avoided as they go against expectation
|
||||
lint_non_local_definitions_impl_move_help =
|
||||
move the `impl` block outside of this {$body_kind_descr} {$depth ->
|
||||
[one] `{$body_name}`
|
||||
*[other] `{$body_name}` and up {$depth} bodies
|
||||
}
|
||||
|
||||
lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module
|
||||
.help =
|
||||
remove the `#[macro_export]` or move this `macro_rules!` outside the of the current {$body_kind_descr} {$depth ->
|
||||
[one] `{$body_name}`
|
||||
@ -561,7 +562,12 @@ lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, th
|
||||
.help_doctest =
|
||||
remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}`
|
||||
.non_local = a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute
|
||||
.exception = one exception to the rule are anon-const (`const _: () = {"{"} ... {"}"}`) at top-level module
|
||||
|
||||
lint_non_local_definitions_may_move = may need to be moved as well
|
||||
|
||||
lint_non_local_definitions_of_trait_not_local = `{$of_trait_str}` is not local
|
||||
|
||||
lint_non_local_definitions_self_ty_not_local = `{$self_ty_str}` is not local
|
||||
|
||||
lint_non_snake_case = {$sort} `{$name}` should have a snake case name
|
||||
.rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier
|
||||
@ -884,6 +890,8 @@ lint_unused_op = unused {$op} that must be used
|
||||
|
||||
lint_unused_result = unused result of type `{$ty}`
|
||||
|
||||
lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result
|
||||
|
||||
lint_variant_size_differences =
|
||||
enum variant is more than three times larger ({$largest} bytes) than the next largest
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rustc_hir::{Arm, Expr, ExprKind, Node};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, Node, StmtKind};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::sym;
|
||||
@ -6,7 +6,7 @@ use rustc_span::sym;
|
||||
use crate::{
|
||||
lints::{
|
||||
DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag, UndroppedManuallyDropsDiag,
|
||||
UndroppedManuallyDropsSuggestion,
|
||||
UndroppedManuallyDropsSuggestion, UseLetUnderscoreIgnoreSuggestion,
|
||||
},
|
||||
LateContext, LateLintPass, LintContext,
|
||||
};
|
||||
@ -148,33 +148,59 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
|
||||
let arg_ty = cx.typeck_results().expr_ty(arg);
|
||||
let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env);
|
||||
let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
|
||||
let let_underscore_ignore_sugg = || {
|
||||
if let Some((_, node)) = cx.tcx.hir().parent_iter(expr.hir_id).nth(0)
|
||||
&& let Node::Stmt(stmt) = node
|
||||
&& let StmtKind::Semi(e) = stmt.kind
|
||||
&& e.hir_id == expr.hir_id
|
||||
{
|
||||
UseLetUnderscoreIgnoreSuggestion::Suggestion {
|
||||
start_span: expr.span.shrink_to_lo().until(arg.span),
|
||||
end_span: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()),
|
||||
}
|
||||
} else {
|
||||
UseLetUnderscoreIgnoreSuggestion::Note
|
||||
}
|
||||
};
|
||||
match fn_name {
|
||||
sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => {
|
||||
cx.emit_span_lint(
|
||||
DROPPING_REFERENCES,
|
||||
expr.span,
|
||||
DropRefDiag { arg_ty, label: arg.span },
|
||||
DropRefDiag { arg_ty, label: arg.span, sugg: let_underscore_ignore_sugg() },
|
||||
);
|
||||
}
|
||||
sym::mem_forget if arg_ty.is_ref() => {
|
||||
cx.emit_span_lint(
|
||||
FORGETTING_REFERENCES,
|
||||
expr.span,
|
||||
ForgetRefDiag { arg_ty, label: arg.span },
|
||||
ForgetRefDiag {
|
||||
arg_ty,
|
||||
label: arg.span,
|
||||
sugg: let_underscore_ignore_sugg(),
|
||||
},
|
||||
);
|
||||
}
|
||||
sym::mem_drop if is_copy && !drop_is_single_call_in_arm => {
|
||||
cx.emit_span_lint(
|
||||
DROPPING_COPY_TYPES,
|
||||
expr.span,
|
||||
DropCopyDiag { arg_ty, label: arg.span },
|
||||
DropCopyDiag {
|
||||
arg_ty,
|
||||
label: arg.span,
|
||||
sugg: let_underscore_ignore_sugg(),
|
||||
},
|
||||
);
|
||||
}
|
||||
sym::mem_forget if is_copy => {
|
||||
cx.emit_span_lint(
|
||||
FORGETTING_COPY_TYPES,
|
||||
expr.span,
|
||||
ForgetCopyDiag { arg_ty, label: arg.span },
|
||||
ForgetCopyDiag {
|
||||
arg_ty,
|
||||
label: arg.span,
|
||||
sugg: let_underscore_ignore_sugg(),
|
||||
},
|
||||
);
|
||||
}
|
||||
sym::mem_drop
|
||||
|
@ -6,7 +6,7 @@ use crate::errors::RequestedLevel;
|
||||
use crate::fluent_generated as fluent;
|
||||
use rustc_errors::{
|
||||
codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString,
|
||||
ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, SubdiagMessageOp,
|
||||
ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp,
|
||||
Subdiagnostic, SuggestionStyle,
|
||||
};
|
||||
use rustc_hir::{def::Namespace, def_id::DefId};
|
||||
@ -656,41 +656,62 @@ pub struct ForLoopsOverFalliblesSuggestion<'a> {
|
||||
pub end_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum UseLetUnderscoreIgnoreSuggestion {
|
||||
#[note(lint_use_let_underscore_ignore_suggestion)]
|
||||
Note,
|
||||
#[multipart_suggestion(
|
||||
lint_use_let_underscore_ignore_suggestion,
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Suggestion {
|
||||
#[suggestion_part(code = "let _ = ")]
|
||||
start_span: Span,
|
||||
#[suggestion_part(code = "")]
|
||||
end_span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
// drop_forget_useless.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_dropping_references)]
|
||||
#[note]
|
||||
pub struct DropRefDiag<'a> {
|
||||
pub arg_ty: Ty<'a>,
|
||||
#[label]
|
||||
pub label: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: UseLetUnderscoreIgnoreSuggestion,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_dropping_copy_types)]
|
||||
#[note]
|
||||
pub struct DropCopyDiag<'a> {
|
||||
pub arg_ty: Ty<'a>,
|
||||
#[label]
|
||||
pub label: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: UseLetUnderscoreIgnoreSuggestion,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_forgetting_references)]
|
||||
#[note]
|
||||
pub struct ForgetRefDiag<'a> {
|
||||
pub arg_ty: Ty<'a>,
|
||||
#[label]
|
||||
pub label: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: UseLetUnderscoreIgnoreSuggestion,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_forgetting_copy_types)]
|
||||
#[note]
|
||||
pub struct ForgetCopyDiag<'a> {
|
||||
pub arg_ty: Ty<'a>,
|
||||
#[label]
|
||||
pub label: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: UseLetUnderscoreIgnoreSuggestion,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
@ -1329,40 +1350,126 @@ pub struct SuspiciousDoubleRefCloneDiag<'a> {
|
||||
}
|
||||
|
||||
// non_local_defs.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
pub enum NonLocalDefinitionsDiag {
|
||||
#[diag(lint_non_local_definitions_impl)]
|
||||
#[help]
|
||||
#[note(lint_non_local)]
|
||||
#[note(lint_exception)]
|
||||
#[note(lint_non_local_definitions_deprecation)]
|
||||
Impl {
|
||||
depth: u32,
|
||||
body_kind_descr: &'static str,
|
||||
body_name: String,
|
||||
#[subdiagnostic]
|
||||
cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>,
|
||||
#[suggestion(lint_const_anon, code = "_", applicability = "machine-applicable")]
|
||||
const_anon: Option<Span>,
|
||||
const_anon: Option<Option<Span>>,
|
||||
move_to: Option<(Span, Vec<Span>)>,
|
||||
may_remove: Option<(Span, String)>,
|
||||
has_trait: bool,
|
||||
self_ty_str: String,
|
||||
of_trait_str: Option<String>,
|
||||
},
|
||||
#[diag(lint_non_local_definitions_macro_rules)]
|
||||
MacroRules {
|
||||
depth: u32,
|
||||
body_kind_descr: &'static str,
|
||||
body_name: String,
|
||||
#[help]
|
||||
help: Option<()>,
|
||||
#[help(lint_help_doctest)]
|
||||
doctest_help: Option<()>,
|
||||
#[note(lint_non_local)]
|
||||
#[note(lint_exception)]
|
||||
#[note(lint_non_local_definitions_deprecation)]
|
||||
notes: (),
|
||||
#[subdiagnostic]
|
||||
cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
|
||||
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
|
||||
match self {
|
||||
NonLocalDefinitionsDiag::Impl {
|
||||
depth,
|
||||
body_kind_descr,
|
||||
body_name,
|
||||
cargo_update,
|
||||
const_anon,
|
||||
move_to,
|
||||
may_remove,
|
||||
has_trait,
|
||||
self_ty_str,
|
||||
of_trait_str,
|
||||
} => {
|
||||
diag.primary_message(fluent::lint_non_local_definitions_impl);
|
||||
diag.arg("depth", depth);
|
||||
diag.arg("body_kind_descr", body_kind_descr);
|
||||
diag.arg("body_name", body_name);
|
||||
diag.arg("self_ty_str", self_ty_str);
|
||||
if let Some(of_trait_str) = of_trait_str {
|
||||
diag.arg("of_trait_str", of_trait_str);
|
||||
}
|
||||
|
||||
if has_trait {
|
||||
diag.note(fluent::lint_bounds);
|
||||
diag.note(fluent::lint_with_trait);
|
||||
} else {
|
||||
diag.note(fluent::lint_without_trait);
|
||||
}
|
||||
|
||||
if let Some((move_help, may_move)) = move_to {
|
||||
let mut ms = MultiSpan::from_span(move_help);
|
||||
for sp in may_move {
|
||||
ms.push_span_label(sp, fluent::lint_non_local_definitions_may_move);
|
||||
}
|
||||
diag.span_help(ms, fluent::lint_non_local_definitions_impl_move_help);
|
||||
}
|
||||
|
||||
if let Some((span, part)) = may_remove {
|
||||
diag.arg("may_remove_part", part);
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
fluent::lint_remove_help,
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(cargo_update) = cargo_update {
|
||||
diag.subdiagnostic(&diag.dcx, cargo_update);
|
||||
}
|
||||
if let Some(const_anon) = const_anon {
|
||||
diag.note(fluent::lint_exception);
|
||||
if let Some(const_anon) = const_anon {
|
||||
diag.span_suggestion(
|
||||
const_anon,
|
||||
fluent::lint_const_anon,
|
||||
"_",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
diag.note(fluent::lint_non_local_definitions_deprecation);
|
||||
}
|
||||
NonLocalDefinitionsDiag::MacroRules {
|
||||
depth,
|
||||
body_kind_descr,
|
||||
body_name,
|
||||
help,
|
||||
doctest_help,
|
||||
cargo_update,
|
||||
} => {
|
||||
diag.primary_message(fluent::lint_non_local_definitions_macro_rules);
|
||||
diag.arg("depth", depth);
|
||||
diag.arg("body_kind_descr", body_kind_descr);
|
||||
diag.arg("body_name", body_name);
|
||||
|
||||
if let Some(()) = help {
|
||||
diag.help(fluent::lint_help);
|
||||
}
|
||||
if let Some(()) = doctest_help {
|
||||
diag.help(fluent::lint_help_doctest);
|
||||
}
|
||||
|
||||
diag.note(fluent::lint_non_local);
|
||||
diag.note(fluent::lint_non_local_definitions_deprecation);
|
||||
|
||||
if let Some(cargo_update) = cargo_update {
|
||||
diag.subdiagnostic(&diag.dcx, cargo_update);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(lint_non_local_definitions_cargo_update)]
|
||||
pub struct NonLocalDefinitionsCargoUpdateNote {
|
||||
|
@ -1,3 +1,6 @@
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, TyKind};
|
||||
use rustc_hir::{Path, QPath};
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
@ -7,12 +10,13 @@ use rustc_middle::ty::{EarlyBinder, TraitRef, TypeSuperFoldable};
|
||||
use rustc_session::{declare_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind};
|
||||
use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind, Symbol};
|
||||
use rustc_trait_selection::infer::TyCtxtInferExt;
|
||||
use rustc_trait_selection::traits::error_reporting::ambiguity::{
|
||||
compute_applicable_impls_for_diagnostics, CandidateSource,
|
||||
};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
|
||||
@ -134,35 +138,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
||||
};
|
||||
|
||||
// Part 1: Is the Self type local?
|
||||
let self_ty_has_local_parent = match impl_.self_ty.kind {
|
||||
TyKind::Path(QPath::Resolved(_, ty_path)) => {
|
||||
path_has_local_parent(ty_path, cx, parent, parent_parent)
|
||||
}
|
||||
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
|
||||
path_has_local_parent(
|
||||
principle_poly_trait_ref.trait_ref.path,
|
||||
cx,
|
||||
parent,
|
||||
parent_parent,
|
||||
)
|
||||
}
|
||||
TyKind::TraitObject([], _, _)
|
||||
| TyKind::InferDelegation(_, _)
|
||||
| TyKind::Slice(_)
|
||||
| TyKind::Array(_, _)
|
||||
| TyKind::Ptr(_)
|
||||
| TyKind::Ref(_, _)
|
||||
| TyKind::BareFn(_)
|
||||
| TyKind::Never
|
||||
| TyKind::Tup(_)
|
||||
| TyKind::Path(_)
|
||||
| TyKind::Pat(..)
|
||||
| TyKind::AnonAdt(_)
|
||||
| TyKind::OpaqueDef(_, _, _)
|
||||
| TyKind::Typeof(_)
|
||||
| TyKind::Infer
|
||||
| TyKind::Err(_) => false,
|
||||
};
|
||||
let self_ty_has_local_parent =
|
||||
ty_has_local_parent(&impl_.self_ty.kind, cx, parent, parent_parent);
|
||||
|
||||
if self_ty_has_local_parent {
|
||||
return;
|
||||
@ -202,8 +179,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
||||
// Get the span of the parent const item ident (if it's a not a const anon).
|
||||
//
|
||||
// Used to suggest changing the const item to a const anon.
|
||||
let span_for_const_anon_suggestion = if self.body_depth == 1
|
||||
&& parent_def_kind == DefKind::Const
|
||||
let span_for_const_anon_suggestion = if parent_def_kind == DefKind::Const
|
||||
&& parent_opt_item_name != Some(kw::Underscore)
|
||||
&& let Some(parent) = parent.as_local()
|
||||
&& let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent)
|
||||
@ -215,9 +191,76 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
||||
None
|
||||
};
|
||||
|
||||
let mut collector = PathCollector { paths: Vec::new() };
|
||||
collector.visit_ty(&impl_.self_ty);
|
||||
if let Some(of_trait) = &impl_.of_trait {
|
||||
collector.visit_trait_ref(of_trait);
|
||||
}
|
||||
collector.visit_generics(&impl_.generics);
|
||||
|
||||
let mut may_move: Vec<Span> = collector
|
||||
.paths
|
||||
.into_iter()
|
||||
.filter_map(|path| {
|
||||
if let Some(did) = path.res.opt_def_id()
|
||||
&& did_has_local_parent(did, cx.tcx, parent, parent_parent)
|
||||
{
|
||||
Some(cx.tcx.def_span(did))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
may_move.sort();
|
||||
may_move.dedup();
|
||||
|
||||
let const_anon = matches!(parent_def_kind, DefKind::Const | DefKind::Static { .. })
|
||||
.then_some(span_for_const_anon_suggestion);
|
||||
|
||||
let may_remove = match &impl_.self_ty.kind {
|
||||
TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty)
|
||||
if ty_has_local_parent(&mut_ty.ty.kind, cx, parent, parent_parent) =>
|
||||
{
|
||||
let type_ =
|
||||
if matches!(impl_.self_ty.kind, TyKind::Ptr(_)) { "*" } else { "&" };
|
||||
let part = format!("{}{}", type_, mut_ty.mutbl.prefix_str());
|
||||
Some((impl_.self_ty.span.shrink_to_lo().until(mut_ty.ty.span), part))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let impl_span = item.span.shrink_to_lo().to(impl_.self_ty.span);
|
||||
let mut ms = MultiSpan::from_span(impl_span);
|
||||
|
||||
let (self_ty_span, self_ty_str) =
|
||||
self_ty_kind_for_diagnostic(&impl_.self_ty, cx.tcx);
|
||||
|
||||
ms.push_span_label(
|
||||
self_ty_span,
|
||||
fluent::lint_non_local_definitions_self_ty_not_local,
|
||||
);
|
||||
let of_trait_str = if let Some(of_trait) = &impl_.of_trait {
|
||||
ms.push_span_label(
|
||||
path_span_without_args(&of_trait.path),
|
||||
fluent::lint_non_local_definitions_of_trait_not_local,
|
||||
);
|
||||
Some(path_name_to_string(&of_trait.path))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let move_to = if may_move.is_empty() {
|
||||
ms.push_span_label(
|
||||
cx.tcx.def_span(parent),
|
||||
fluent::lint_non_local_definitions_impl_move_help,
|
||||
);
|
||||
None
|
||||
} else {
|
||||
Some((cx.tcx.def_span(parent), may_move))
|
||||
};
|
||||
|
||||
cx.emit_span_lint(
|
||||
NON_LOCAL_DEFINITIONS,
|
||||
item.span,
|
||||
ms,
|
||||
NonLocalDefinitionsDiag::Impl {
|
||||
depth: self.body_depth,
|
||||
body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent),
|
||||
@ -225,7 +268,12 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
||||
.map(|s| s.to_ident_string())
|
||||
.unwrap_or_else(|| "<unnameable>".to_string()),
|
||||
cargo_update: cargo_update(),
|
||||
const_anon: span_for_const_anon_suggestion,
|
||||
const_anon,
|
||||
self_ty_str,
|
||||
of_trait_str,
|
||||
move_to,
|
||||
may_remove,
|
||||
has_trait: impl_.of_trait.is_some(),
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -250,7 +298,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
||||
cargo_update: cargo_update(),
|
||||
help: (!is_at_toplevel_doctest).then_some(()),
|
||||
doctest_help: is_at_toplevel_doctest.then_some(()),
|
||||
notes: (),
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -343,6 +390,54 @@ impl<'a, 'tcx, F: FnMut(DefId) -> bool> TypeFolder<TyCtxt<'tcx>>
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple hir::Path collector
|
||||
struct PathCollector<'tcx> {
|
||||
paths: Vec<Path<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> {
|
||||
fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
|
||||
self.paths.push(path.clone()); // need to clone, bc of the restricted lifetime
|
||||
intravisit::walk_path(self, path)
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a `Ty` we check if the (outermost) type is local.
|
||||
fn ty_has_local_parent(
|
||||
ty_kind: &TyKind<'_>,
|
||||
cx: &LateContext<'_>,
|
||||
impl_parent: DefId,
|
||||
impl_parent_parent: Option<DefId>,
|
||||
) -> bool {
|
||||
match ty_kind {
|
||||
TyKind::Path(QPath::Resolved(_, ty_path)) => {
|
||||
path_has_local_parent(ty_path, cx, impl_parent, impl_parent_parent)
|
||||
}
|
||||
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => path_has_local_parent(
|
||||
principle_poly_trait_ref.trait_ref.path,
|
||||
cx,
|
||||
impl_parent,
|
||||
impl_parent_parent,
|
||||
),
|
||||
TyKind::TraitObject([], _, _)
|
||||
| TyKind::InferDelegation(_, _)
|
||||
| TyKind::Slice(_)
|
||||
| TyKind::Array(_, _)
|
||||
| TyKind::Ptr(_)
|
||||
| TyKind::Ref(_, _)
|
||||
| TyKind::BareFn(_)
|
||||
| TyKind::Never
|
||||
| TyKind::Tup(_)
|
||||
| TyKind::Path(_)
|
||||
| TyKind::Pat(..)
|
||||
| TyKind::AnonAdt(_)
|
||||
| TyKind::OpaqueDef(_, _, _)
|
||||
| TyKind::Typeof(_)
|
||||
| TyKind::Infer
|
||||
| TyKind::Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a path and a parent impl def id, this checks if the if parent resolution
|
||||
/// def id correspond to the def id of the parent impl definition.
|
||||
///
|
||||
@ -384,3 +479,52 @@ fn did_has_local_parent(
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Return for a given `Path` the span until the last args
|
||||
fn path_span_without_args(path: &Path<'_>) -> Span {
|
||||
if let Some(args) = &path.segments.last().unwrap().args {
|
||||
path.span.until(args.span_ext)
|
||||
} else {
|
||||
path.span
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a "error message-able" ident for the last segment of the `Path`
|
||||
fn path_name_to_string(path: &Path<'_>) -> String {
|
||||
path.segments.last().unwrap().ident.name.to_ident_string()
|
||||
}
|
||||
|
||||
/// Compute the `Span` and visual representation for the `Self` we want to point at;
|
||||
/// It follows part of the actual logic of non-local, and if possible return the least
|
||||
/// amount possible for the span and representation.
|
||||
fn self_ty_kind_for_diagnostic(ty: &rustc_hir::Ty<'_>, tcx: TyCtxt<'_>) -> (Span, String) {
|
||||
match ty.kind {
|
||||
TyKind::Path(QPath::Resolved(_, ty_path)) => (
|
||||
path_span_without_args(ty_path),
|
||||
ty_path
|
||||
.res
|
||||
.opt_def_id()
|
||||
.map(|did| tcx.opt_item_name(did))
|
||||
.flatten()
|
||||
.as_ref()
|
||||
.map(|s| Symbol::as_str(s))
|
||||
.unwrap_or("<unnameable>")
|
||||
.to_string(),
|
||||
),
|
||||
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
|
||||
let path = &principle_poly_trait_ref.trait_ref.path;
|
||||
(
|
||||
path_span_without_args(path),
|
||||
path.res
|
||||
.opt_def_id()
|
||||
.map(|did| tcx.opt_item_name(did))
|
||||
.flatten()
|
||||
.as_ref()
|
||||
.map(|s| Symbol::as_str(s))
|
||||
.unwrap_or("<unnameable>")
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
_ => (ty.span, rustc_hir_pretty::ty_to_string(&tcx, ty)),
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +321,7 @@ impl<'hir> Map<'hir> {
|
||||
|
||||
/// Returns an iterator of the `DefId`s for all body-owners in this
|
||||
/// crate. If you would prefer to iterate over the bodies
|
||||
/// themselves, you can do `self.hir().krate().body_ids.iter()`.
|
||||
/// themselves, you can do `self.hir().krate().owners.iter()`.
|
||||
#[inline]
|
||||
pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir {
|
||||
self.tcx.hir_crate_items(()).body_owners.iter().copied()
|
||||
@ -508,7 +508,17 @@ impl<'hir> Map<'hir> {
|
||||
/// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
|
||||
/// Used exclusively for diagnostics, to avoid suggestion function calls.
|
||||
pub fn is_inside_const_context(self, hir_id: HirId) -> bool {
|
||||
self.body_const_context(self.enclosing_body_owner(hir_id)).is_some()
|
||||
for (_, node) in self.parent_iter(hir_id) {
|
||||
if let Some((def_id, _)) = node.associated_body() {
|
||||
return self.body_const_context(def_id).is_some();
|
||||
}
|
||||
if let Node::Expr(e) = node {
|
||||
if let ExprKind::ConstBlock(_) = e.kind {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is
|
||||
@ -891,7 +901,6 @@ impl<'hir> Map<'hir> {
|
||||
Node::Variant(variant) => variant.span,
|
||||
Node::Field(field) => field.span,
|
||||
Node::AnonConst(constant) => constant.span,
|
||||
Node::ConstBlock(constant) => self.body(constant.body).value.span,
|
||||
Node::Expr(expr) => expr.span,
|
||||
Node::ExprField(field) => field.span,
|
||||
Node::Stmt(stmt) => stmt.span,
|
||||
@ -1161,7 +1170,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
|
||||
format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id))
|
||||
}
|
||||
Node::AnonConst(_) => node_str("const"),
|
||||
Node::ConstBlock(_) => node_str("const"),
|
||||
Node::Expr(_) => node_str("expr"),
|
||||
Node::ExprField(_) => node_str("expr field"),
|
||||
Node::Stmt(_) => node_str("stmt"),
|
||||
@ -1311,11 +1319,6 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
|
||||
intravisit::walk_anon_const(self, c)
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, c: &'hir ConstBlock) {
|
||||
self.body_owners.push(c.def_id);
|
||||
intravisit::walk_inline_const(self, c)
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'hir Expr<'hir>) {
|
||||
if let ExprKind::Closure(closure) = ex.kind {
|
||||
self.body_owners.push(closure.def_id);
|
||||
|
@ -266,19 +266,6 @@ impl AllocRange {
|
||||
|
||||
// The constructors are all without extra; the extra gets added by a machine hook later.
|
||||
impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
||||
/// Creates an allocation from an existing `Bytes` value - this is needed for miri FFI support
|
||||
pub fn from_raw_bytes(bytes: Bytes, align: Align, mutability: Mutability) -> Self {
|
||||
let size = Size::from_bytes(bytes.len());
|
||||
Self {
|
||||
bytes,
|
||||
provenance: ProvenanceMap::new(),
|
||||
init_mask: InitMask::new(size, true),
|
||||
align,
|
||||
mutability,
|
||||
extra: (),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an allocation initialized by the given bytes
|
||||
pub fn from_bytes<'a>(
|
||||
slice: impl Into<Cow<'a, [u8]>>,
|
||||
@ -342,18 +329,30 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
||||
Err(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add the extra.
|
||||
pub fn with_extra<Extra>(self, extra: Extra) -> Allocation<Prov, Extra, Bytes> {
|
||||
Allocation {
|
||||
bytes: self.bytes,
|
||||
provenance: self.provenance,
|
||||
init_mask: self.init_mask,
|
||||
align: self.align,
|
||||
mutability: self.mutability,
|
||||
extra,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Allocation {
|
||||
/// Adjust allocation from the ones in `tcx` to a custom Machine instance
|
||||
/// with a different `Provenance`, `Extra` and `Byte` type.
|
||||
pub fn adjust_from_tcx<Prov: Provenance, Extra, Bytes: AllocBytes, Err>(
|
||||
self,
|
||||
/// with a different `Provenance` and `Byte` type.
|
||||
pub fn adjust_from_tcx<Prov: Provenance, Bytes: AllocBytes, Err>(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
extra: Extra,
|
||||
mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> Result<Pointer<Prov>, Err>,
|
||||
) -> Result<Allocation<Prov, Extra, Bytes>, Err> {
|
||||
let mut bytes = self.bytes;
|
||||
) -> Result<Allocation<Prov, (), Bytes>, Err> {
|
||||
// Copy the data.
|
||||
let mut bytes = Bytes::from_bytes(Cow::Borrowed(&*self.bytes), self.align);
|
||||
// Adjust provenance of pointers stored in this allocation.
|
||||
let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len());
|
||||
let ptr_size = cx.data_layout().pointer_size.bytes_usize();
|
||||
@ -369,12 +368,12 @@ impl Allocation {
|
||||
}
|
||||
// Create allocation.
|
||||
Ok(Allocation {
|
||||
bytes: AllocBytes::from_bytes(Cow::Owned(Vec::from(bytes)), self.align),
|
||||
bytes,
|
||||
provenance: ProvenanceMap::from_presorted_ptrs(new_provenance),
|
||||
init_mask: self.init_mask,
|
||||
init_mask: self.init_mask.clone(),
|
||||
align: self.align,
|
||||
mutability: self.mutability,
|
||||
extra,
|
||||
extra: self.extra,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1434,6 +1434,13 @@ pub enum UnOp {
|
||||
Not,
|
||||
/// The `-` operator for negation
|
||||
Neg,
|
||||
/// Get the metadata `M` from a `*const/mut impl Pointee<Metadata = M>`.
|
||||
///
|
||||
/// For example, this will give a `()` from `*const i32`, a `usize` from
|
||||
/// `*mut [u8]`, or a pointer to a vtable from a `*const dyn Foo`.
|
||||
///
|
||||
/// Allowed only in [`MirPhase::Runtime`]; earlier it's an intrinsic.
|
||||
PtrMetadata,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
|
||||
|
@ -180,7 +180,10 @@ impl<'tcx> Rvalue<'tcx> {
|
||||
let rhs_ty = rhs.ty(local_decls, tcx);
|
||||
op.ty(tcx, lhs_ty, rhs_ty)
|
||||
}
|
||||
Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
|
||||
Rvalue::UnaryOp(op, ref operand) => {
|
||||
let arg_ty = operand.ty(local_decls, tcx);
|
||||
op.ty(tcx, arg_ty)
|
||||
}
|
||||
Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
|
||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
|
||||
tcx.types.usize
|
||||
@ -282,6 +285,27 @@ impl<'tcx> BinOp {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UnOp {
|
||||
pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match self {
|
||||
UnOp::Not | UnOp::Neg => arg_ty,
|
||||
UnOp::PtrMetadata => {
|
||||
let pointee_ty = arg_ty
|
||||
.builtin_deref(true)
|
||||
.unwrap_or_else(|| bug!("PtrMetadata of non-dereferenceable ty {arg_ty:?}"));
|
||||
if pointee_ty.is_trivially_sized(tcx) {
|
||||
tcx.types.unit
|
||||
} else {
|
||||
let Some(metadata_def_id) = tcx.lang_items().metadata_type() else {
|
||||
bug!("No metadata_type lang item while looking at {arg_ty:?}")
|
||||
};
|
||||
Ty::new_projection(tcx, metadata_def_id, [pointee_ty])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BorrowKind {
|
||||
pub fn to_mutbl_lossy(self) -> hir::Mutability {
|
||||
match self {
|
||||
|
@ -218,6 +218,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
self.check_and_mk_args(def_id, args)
|
||||
}
|
||||
|
||||
fn intern_canonical_goal_evaluation_step(
|
||||
self,
|
||||
step: solve::inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>,
|
||||
) -> &'tcx solve::inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>> {
|
||||
self.arena.alloc(step)
|
||||
}
|
||||
|
||||
fn parent(self, def_id: Self::DefId) -> Self::DefId {
|
||||
self.parent(def_id)
|
||||
}
|
||||
@ -737,6 +744,7 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
|
||||
1,
|
||||
),
|
||||
bodies,
|
||||
has_inline_consts: false,
|
||||
})));
|
||||
self.feed_owner_id().hir_attrs(attrs);
|
||||
}
|
||||
|
@ -121,17 +121,14 @@ impl<'tcx> Predicate<'tcx> {
|
||||
#[inline]
|
||||
pub fn allow_normalization(self) -> bool {
|
||||
match self.kind().skip_binder() {
|
||||
PredicateKind::Clause(ClauseKind::WellFormed(_)) => false,
|
||||
// `NormalizesTo` is only used in the new solver, so this shouldn't
|
||||
// matter. Normalizing `term` would be 'wrong' however, as it changes whether
|
||||
// `normalizes-to(<T as Trait>::Assoc, <T as Trait>::Assoc)` holds.
|
||||
PredicateKind::NormalizesTo(..) => false,
|
||||
PredicateKind::Clause(ClauseKind::WellFormed(_))
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::NormalizesTo(..) => false,
|
||||
PredicateKind::Clause(ClauseKind::Trait(_))
|
||||
| PredicateKind::Clause(ClauseKind::RegionOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::TypeOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::Projection(_))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::ObjectSafe(_)
|
||||
| PredicateKind::Subtype(_)
|
||||
| PredicateKind::Coerce(_)
|
||||
|
@ -1579,8 +1579,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||
let formatted_op = match op {
|
||||
UnOp::Not => "!",
|
||||
UnOp::Neg => "-",
|
||||
UnOp::PtrMetadata => "PtrMetadata",
|
||||
};
|
||||
let parenthesized = match ct.kind() {
|
||||
_ if op == UnOp::PtrMetadata => true,
|
||||
ty::ConstKind::Expr(Expr::UnOp(c_op, ..)) => c_op != op,
|
||||
ty::ConstKind::Expr(_) => true,
|
||||
_ => false,
|
||||
|
@ -217,6 +217,10 @@ pub struct TypeckResults<'tcx> {
|
||||
|
||||
/// Container types and field indices of `offset_of!` expressions
|
||||
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>,
|
||||
|
||||
/// Maps from `HirId`s of const blocks (the `ExprKind::ConstBlock`, not the inner expression's)
|
||||
/// to the `DefId` of the corresponding inline const.
|
||||
pub inline_consts: FxIndexMap<ItemLocalId, LocalDefId>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeckResults<'tcx> {
|
||||
@ -249,6 +253,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||
treat_byte_string_as_slice: Default::default(),
|
||||
closure_size_eval: Default::default(),
|
||||
offset_of_data: Default::default(),
|
||||
inline_consts: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,10 +84,14 @@ pub(super) fn vtable_allocation_provider<'tcx>(
|
||||
let idx: u64 = u64::try_from(idx).unwrap();
|
||||
let scalar = match entry {
|
||||
VtblEntry::MetadataDropInPlace => {
|
||||
let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
|
||||
let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance);
|
||||
let fn_ptr = Pointer::from(fn_alloc_id);
|
||||
Scalar::from_pointer(fn_ptr, &tcx)
|
||||
if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
|
||||
let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
|
||||
let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance);
|
||||
let fn_ptr = Pointer::from(fn_alloc_id);
|
||||
Scalar::from_pointer(fn_ptr, &tcx)
|
||||
} else {
|
||||
Scalar::from_maybe_pointer(Pointer::null(), &tcx)
|
||||
}
|
||||
}
|
||||
VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size),
|
||||
VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size),
|
||||
|
@ -157,6 +157,63 @@ impl BranchInfoBuilder {
|
||||
}
|
||||
|
||||
impl<'tcx> Builder<'_, 'tcx> {
|
||||
/// If condition coverage is enabled, inject extra blocks and marker statements
|
||||
/// that will let us track the value of the condition in `place`.
|
||||
pub(crate) fn visit_coverage_standalone_condition(
|
||||
&mut self,
|
||||
mut expr_id: ExprId, // Expression giving the span of the condition
|
||||
place: mir::Place<'tcx>, // Already holds the boolean condition value
|
||||
block: &mut BasicBlock,
|
||||
) {
|
||||
// Bail out if condition coverage is not enabled for this function.
|
||||
let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
|
||||
if !self.tcx.sess.instrument_coverage_condition() {
|
||||
return;
|
||||
};
|
||||
|
||||
// Remove any wrappers, so that we can inspect the real underlying expression.
|
||||
while let ExprKind::Use { source: inner } | ExprKind::Scope { value: inner, .. } =
|
||||
self.thir[expr_id].kind
|
||||
{
|
||||
expr_id = inner;
|
||||
}
|
||||
// If the expression is a lazy logical op, it will naturally get branch
|
||||
// coverage as part of its normal lowering, so we can disregard it here.
|
||||
if let ExprKind::LogicalOp { .. } = self.thir[expr_id].kind {
|
||||
return;
|
||||
}
|
||||
|
||||
let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope };
|
||||
|
||||
// Using the boolean value that has already been stored in `place`, set up
|
||||
// control flow in the shape of a diamond, so that we can place separate
|
||||
// marker statements in the true and false blocks. The coverage MIR pass
|
||||
// will use those markers to inject coverage counters as appropriate.
|
||||
//
|
||||
// block
|
||||
// / \
|
||||
// true_block false_block
|
||||
// (marker) (marker)
|
||||
// \ /
|
||||
// join_block
|
||||
|
||||
let true_block = self.cfg.start_new_block();
|
||||
let false_block = self.cfg.start_new_block();
|
||||
self.cfg.terminate(
|
||||
*block,
|
||||
source_info,
|
||||
mir::TerminatorKind::if_(mir::Operand::Copy(place), true_block, false_block),
|
||||
);
|
||||
|
||||
branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block);
|
||||
|
||||
let join_block = self.cfg.start_new_block();
|
||||
self.cfg.goto(true_block, source_info, join_block);
|
||||
self.cfg.goto(false_block, source_info, join_block);
|
||||
// Any subsequent codegen in the caller should use the new join block.
|
||||
*block = join_block;
|
||||
}
|
||||
|
||||
/// If branch coverage is enabled, inject marker statements into `then_block`
|
||||
/// and `else_block`, and record their IDs in the table of branch spans.
|
||||
pub(crate) fn visit_coverage_branch_condition(
|
||||
|
@ -217,12 +217,13 @@ impl MCDCInfoBuilder {
|
||||
}
|
||||
_ => {
|
||||
// Do not generate mcdc mappings and statements for decisions with too many conditions.
|
||||
let rebase_idx = self.branch_spans.len() - decision.conditions_num + 1;
|
||||
// Therefore, first erase the condition info of the (N-1) previous branch spans.
|
||||
let rebase_idx = self.branch_spans.len() - (decision.conditions_num - 1);
|
||||
for branch in &mut self.branch_spans[rebase_idx..] {
|
||||
branch.condition_info = None;
|
||||
}
|
||||
|
||||
// ConditionInfo of this branch shall also be reset.
|
||||
// Then, erase this last branch span's info too, for a total of N.
|
||||
condition_info = None;
|
||||
|
||||
tcx.dcx().emit_warn(MCDCExceedsConditionNumLimit {
|
||||
|
@ -212,6 +212,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
|
||||
},
|
||||
@call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
|
||||
@call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)),
|
||||
@call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
|
||||
ExprKind::Borrow { borrow_kind, arg } => Ok(
|
||||
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
|
||||
|
@ -183,9 +183,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
const_: Const::from_bool(this.tcx, constant),
|
||||
},
|
||||
);
|
||||
let rhs = unpack!(this.expr_into_dest(destination, continuation, rhs));
|
||||
let mut rhs_block = unpack!(this.expr_into_dest(destination, continuation, rhs));
|
||||
// Instrument the lowered RHS's value for condition coverage.
|
||||
// (Does nothing if condition coverage is not enabled.)
|
||||
this.visit_coverage_standalone_condition(rhs, destination, &mut rhs_block);
|
||||
|
||||
let target = this.cfg.start_new_block();
|
||||
this.cfg.goto(rhs, source_info, target);
|
||||
this.cfg.goto(rhs_block, source_info, target);
|
||||
this.cfg.goto(short_circuit, source_info, target);
|
||||
target.unit()
|
||||
}
|
||||
|
@ -568,11 +568,8 @@ fn construct_const<'a, 'tcx>(
|
||||
..
|
||||
}) => (*span, ty.span),
|
||||
Node::AnonConst(ct) => (ct.span, ct.span),
|
||||
Node::ConstBlock(_) => {
|
||||
let span = tcx.def_span(def);
|
||||
(span, span)
|
||||
}
|
||||
_ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
|
||||
Node::Expr(&hir::Expr { span, kind: hir::ExprKind::ConstBlock(_), .. }) => (span, span),
|
||||
node => span_bug!(tcx.def_span(def), "can't build MIR for {def:?}: {node:#?}"),
|
||||
};
|
||||
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
|
@ -671,9 +671,9 @@ impl<'tcx> Cx<'tcx> {
|
||||
ExprKind::OffsetOf { container, fields }
|
||||
}
|
||||
|
||||
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||
let ty = self.typeck_results().node_type(anon_const.hir_id);
|
||||
let did = anon_const.def_id.to_def_id();
|
||||
hir::ExprKind::ConstBlock(body) => {
|
||||
let ty = self.typeck_results().node_type(body.hir_id);
|
||||
let did = self.typeck_results().inline_consts[&expr.hir_id.local_id].into();
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(did);
|
||||
let parent_args =
|
||||
tcx.erase_regions(GenericArgs::identity_for_item(tcx, typeck_root_def_id));
|
||||
|
@ -13,10 +13,10 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::{self, RvalueScopes, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use tracing::instrument;
|
||||
|
||||
pub(crate) fn thir_body(
|
||||
@ -24,7 +24,22 @@ pub(crate) fn thir_body(
|
||||
owner_def: LocalDefId,
|
||||
) -> Result<(&Steal<Thir<'_>>, ExprId), ErrorGuaranteed> {
|
||||
let hir = tcx.hir();
|
||||
let body = hir.body(hir.body_owned_by(owner_def));
|
||||
let body;
|
||||
let body = match tcx.def_kind(owner_def) {
|
||||
// Inline consts do not have bodies of their own, so create one to make the follow-up logic simpler.
|
||||
DefKind::InlineConst => {
|
||||
let e = hir.expect_expr(tcx.local_def_id_to_hir_id(owner_def));
|
||||
body = hir::Body {
|
||||
params: &[],
|
||||
value: match e.kind {
|
||||
hir::ExprKind::ConstBlock(body) => body,
|
||||
_ => span_bug!(e.span, "InlineConst was not a ConstBlock: {e:#?}"),
|
||||
},
|
||||
};
|
||||
&body
|
||||
}
|
||||
_ => hir.body(hir.body_owned_by(owner_def)),
|
||||
};
|
||||
let mut cx = Cx::new(tcx, owner_def);
|
||||
if let Some(reported) = cx.typeck_results.tainted_by_errors {
|
||||
return Err(reported);
|
||||
@ -165,7 +180,7 @@ impl<'tcx> Cx<'tcx> {
|
||||
&'a mut self,
|
||||
owner_id: HirId,
|
||||
fn_decl: &'tcx hir::FnDecl<'tcx>,
|
||||
body: &'tcx hir::Body<'tcx>,
|
||||
body: &hir::Body<'tcx>,
|
||||
) -> impl Iterator<Item = Param<'tcx>> + 'a {
|
||||
let fn_sig = self.typeck_results.liberated_fn_sigs()[owner_id];
|
||||
|
||||
|
@ -637,15 +637,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
/// Converts inline const patterns.
|
||||
fn lower_inline_const(
|
||||
&mut self,
|
||||
block: &'tcx hir::ConstBlock,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
id: hir::HirId,
|
||||
span: Span,
|
||||
) -> PatKind<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let def_id = block.def_id;
|
||||
let body_id = block.body;
|
||||
let expr = &tcx.hir().body(body_id).value;
|
||||
let ty = tcx.typeck(def_id).node_type(block.hir_id);
|
||||
let def_id = self.typeck_results.inline_consts[&id.local_id];
|
||||
let ty = tcx.typeck(def_id).node_type(expr.hir_id);
|
||||
|
||||
// Special case inline consts that are just literals. This is solely
|
||||
// a performance optimization, as we could also just go through the regular
|
||||
|
@ -219,10 +219,8 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
|
||||
for (i, field) in variant.fields.iter_enumerated() {
|
||||
let field_ty = field.ty(self.tcx, args);
|
||||
if field_ty == *cast_ty {
|
||||
let place = place.project_deeper(
|
||||
&[ProjectionElem::Field(i, *cast_ty)],
|
||||
self.tcx,
|
||||
);
|
||||
let place = place
|
||||
.project_deeper(&[ProjectionElem::Field(i, *cast_ty)], self.tcx);
|
||||
let operand = if operand.is_move() {
|
||||
Operand::Move(place)
|
||||
} else {
|
||||
|
@ -211,7 +211,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
|
||||
}
|
||||
|
||||
fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
tcx.mir_keys(()).contains(&def_id)
|
||||
tcx.hir().maybe_body_owned_by(def_id).is_some()
|
||||
}
|
||||
|
||||
/// Finds the full set of `DefId`s within the current crate that have
|
||||
@ -222,6 +222,15 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
|
||||
// All body-owners have MIR associated with them.
|
||||
set.extend(tcx.hir().body_owners());
|
||||
|
||||
// Inline consts' bodies are created in
|
||||
// typeck instead of during ast lowering, like all other bodies so far.
|
||||
for def_id in tcx.hir().body_owners() {
|
||||
// Incremental performance optimization: only load typeck results for things that actually have inline consts
|
||||
if tcx.hir_owner_nodes(tcx.hir().body_owned_by(def_id).hir_id.owner).has_inline_consts {
|
||||
set.extend(tcx.typeck(def_id).inline_consts.values())
|
||||
}
|
||||
}
|
||||
|
||||
// Additionally, tuple struct/variant constructors have MIR, but
|
||||
// they don't have a BodyId, so we need to build them separately.
|
||||
struct GatherCtors<'a> {
|
||||
|
@ -316,6 +316,23 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
||||
|
||||
terminator.kind = TerminatorKind::Goto { target };
|
||||
}
|
||||
sym::ptr_metadata => {
|
||||
let Ok([ptr]) = <[_; 1]>::try_from(std::mem::take(args)) else {
|
||||
span_bug!(
|
||||
terminator.source_info.span,
|
||||
"Wrong number of arguments for ptr_metadata intrinsic",
|
||||
);
|
||||
};
|
||||
let target = target.unwrap();
|
||||
block.statements.push(Statement {
|
||||
source_info: terminator.source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
*destination,
|
||||
Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node),
|
||||
))),
|
||||
});
|
||||
terminator.kind = TerminatorKind::Goto { target };
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -464,7 +464,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
Rvalue::UnaryOp(op, operand) => {
|
||||
match op {
|
||||
// These operations can never fail.
|
||||
UnOp::Neg | UnOp::Not => {}
|
||||
UnOp::Neg | UnOp::Not | UnOp::PtrMetadata => {}
|
||||
}
|
||||
|
||||
self.validate_operand(operand)?;
|
||||
|
@ -691,7 +691,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
location,
|
||||
format!(
|
||||
"You can't project to field {f:?} of `DynMetadata` because \
|
||||
layout is weird and thinks it doesn't have fields."
|
||||
layout is weird and thinks it doesn't have fields."
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -1109,6 +1109,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
ty::Int(..) | ty::Uint(..) | ty::Bool
|
||||
);
|
||||
}
|
||||
UnOp::PtrMetadata => {
|
||||
if !matches!(self.mir_phase, MirPhase::Runtime(_)) {
|
||||
// It would probably be fine to support this in earlier phases,
|
||||
// but at the time of writing it's only ever introduced from intrinsic lowering,
|
||||
// so earlier things can just `bug!` on it.
|
||||
self.fail(location, "PtrMetadata should be in runtime MIR only");
|
||||
}
|
||||
|
||||
check_kinds!(a, "Cannot PtrMetadata non-pointer type {:?}", ty::RawPtr(..));
|
||||
}
|
||||
}
|
||||
}
|
||||
Rvalue::ShallowInitBox(operand, _) => {
|
||||
|
@ -25,8 +25,8 @@ use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs,
|
||||
Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility,
|
||||
self as ast, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs, Expr,
|
||||
ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility,
|
||||
VisibilityKind, DUMMY_NODE_ID,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
@ -1260,12 +1260,9 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
self.eat_keyword(kw::Const);
|
||||
let (attrs, blk) = self.parse_inner_attrs_and_block()?;
|
||||
let anon_const = AnonConst {
|
||||
id: DUMMY_NODE_ID,
|
||||
value: self.mk_expr(blk.span, ExprKind::Block(blk, None)),
|
||||
};
|
||||
let blk_span = anon_const.value.span;
|
||||
Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(anon_const), attrs))
|
||||
let expr = self.mk_expr(blk.span, ExprKind::Block(blk, None));
|
||||
let blk_span = expr.span;
|
||||
Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(expr), attrs))
|
||||
}
|
||||
|
||||
/// Parses mutability (`mut` or nothing).
|
||||
|
@ -196,11 +196,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
||||
self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) {
|
||||
let kind = Some(hir::ConstContext::Const { inline: true });
|
||||
self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block));
|
||||
}
|
||||
|
||||
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
|
||||
let owner = self.tcx.hir().body_owner_def_id(body.id());
|
||||
let kind = self.tcx.hir().body_const_context(owner);
|
||||
@ -228,6 +223,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
||||
self.const_check_violated(expr, e.span);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::ConstBlock(expr) => {
|
||||
let kind = Some(hir::ConstContext::Const { inline: true });
|
||||
self.recurse_into(kind, None, |this| intravisit::walk_expr(this, expr));
|
||||
return;
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
@ -587,6 +587,16 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
||||
hir::ExprKind::OffsetOf(..) => {
|
||||
self.handle_offset_of(expr);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(expr) => {
|
||||
// When inline const blocks are used in pattern position, paths
|
||||
// referenced by it should be considered as used.
|
||||
let in_pat = mem::replace(&mut self.in_pat, false);
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
|
||||
self.in_pat = in_pat;
|
||||
return;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@ -648,17 +658,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
||||
|
||||
self.in_pat = in_pat;
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
|
||||
// When inline const blocks are used in pattern position, paths
|
||||
// referenced by it should be considered as used.
|
||||
let in_pat = mem::replace(&mut self.in_pat, false);
|
||||
|
||||
self.live_symbols.insert(c.def_id);
|
||||
intravisit::walk_inline_const(self, c);
|
||||
|
||||
self.in_pat = in_pat;
|
||||
}
|
||||
}
|
||||
|
||||
fn has_allow_dead_code_or_lang_attr(
|
||||
|
@ -147,6 +147,11 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't run for inline consts, they are collected together with their parent
|
||||
if let DefKind::InlineConst = tcx.def_kind(def_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't run unused pass for #[naked]
|
||||
if tcx.has_attr(def_id.to_def_id(), sym::naked) {
|
||||
return;
|
||||
@ -1144,12 +1149,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
}
|
||||
|
||||
hir::ExprKind::Lit(..)
|
||||
| hir::ExprKind::ConstBlock(..)
|
||||
| hir::ExprKind::Err(_)
|
||||
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
|
||||
| hir::ExprKind::Path(hir::QPath::LangItem(..))
|
||||
| hir::ExprKind::OffsetOf(..) => succ,
|
||||
|
||||
hir::ExprKind::ConstBlock(expr) => self.propagate_through_expr(expr, succ),
|
||||
|
||||
// Note that labels have been resolved, so we don't need to look
|
||||
// at the label ident
|
||||
hir::ExprKind::Block(ref blk, _) => self.propagate_through_block(blk, succ),
|
||||
|
@ -93,10 +93,6 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||
self.with_context(Constant, |v| intravisit::walk_anon_const(v, c));
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) {
|
||||
self.with_context(Constant, |v| intravisit::walk_inline_const(v, c));
|
||||
}
|
||||
|
||||
fn visit_fn(
|
||||
&mut self,
|
||||
fk: hir::intravisit::FnKind<'hir>,
|
||||
@ -289,6 +285,9 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||
self.cx_stack.len() - 1,
|
||||
)
|
||||
}
|
||||
hir::ExprKind::ConstBlock(expr) => {
|
||||
self.with_context(Constant, |v| intravisit::walk_expr(v, expr));
|
||||
}
|
||||
_ => intravisit::walk_expr(self, e),
|
||||
}
|
||||
}
|
||||
|
@ -325,16 +325,6 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||
ExprKind::Gen(_, _, _) => {
|
||||
self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
|
||||
}
|
||||
ExprKind::ConstBlock(ref constant) => {
|
||||
let def = self.create_def(
|
||||
constant.id,
|
||||
kw::Empty,
|
||||
DefKind::InlineConst,
|
||||
constant.value.span,
|
||||
);
|
||||
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
|
||||
return;
|
||||
}
|
||||
_ => self.parent_def,
|
||||
};
|
||||
|
||||
|
@ -537,6 +537,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
let determined_imports = mem::take(&mut self.determined_imports);
|
||||
let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
|
||||
|
||||
let mut glob_error = false;
|
||||
for (is_indeterminate, import) in determined_imports
|
||||
.iter()
|
||||
.map(|i| (false, i))
|
||||
@ -548,6 +549,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
self.import_dummy_binding(*import, is_indeterminate);
|
||||
|
||||
if let Some(err) = unresolved_import_error {
|
||||
glob_error |= import.is_glob();
|
||||
|
||||
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
|
||||
if source.name == kw::SelfLower {
|
||||
// Silence `unresolved import` error if E0429 is already emitted
|
||||
@ -563,7 +566,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
{
|
||||
// In the case of a new import line, throw a diagnostic message
|
||||
// for the previous line.
|
||||
self.throw_unresolved_import_error(errors);
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
errors = vec![];
|
||||
}
|
||||
if seen_spans.insert(err.span) {
|
||||
@ -574,7 +577,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
|
||||
if !errors.is_empty() {
|
||||
self.throw_unresolved_import_error(errors);
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -600,9 +603,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
if !errors.is_empty() {
|
||||
self.throw_unresolved_import_error(errors);
|
||||
}
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
}
|
||||
|
||||
pub(crate) fn check_hidden_glob_reexports(
|
||||
@ -672,7 +673,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn throw_unresolved_import_error(&mut self, errors: Vec<(Import<'_>, UnresolvedImportError)>) {
|
||||
fn throw_unresolved_import_error(
|
||||
&mut self,
|
||||
errors: Vec<(Import<'_>, UnresolvedImportError)>,
|
||||
glob_error: bool,
|
||||
) {
|
||||
if errors.is_empty() {
|
||||
return;
|
||||
}
|
||||
@ -751,7 +756,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
let guar = diag.emit();
|
||||
if glob_error {
|
||||
self.glob_error = Some(guar);
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to resolve the given import, returning:
|
||||
|
@ -4033,9 +4033,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items.
|
||||
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items or
|
||||
// an invalid `use foo::*;` was found, which can cause unbounded ammounts of "item not found"
|
||||
// errors. We silence them all.
|
||||
fn should_report_errs(&self) -> bool {
|
||||
!(self.r.tcx.sess.opts.actually_rustdoc && self.in_func_body)
|
||||
&& !self.r.glob_error.is_some()
|
||||
}
|
||||
|
||||
// Resolve in alternative namespaces if resolution in the primary namespace fails.
|
||||
@ -4502,8 +4505,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
self.visit_expr(elem);
|
||||
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes));
|
||||
}
|
||||
ExprKind::ConstBlock(ref ct) => {
|
||||
self.resolve_anon_const(ct, AnonConstKind::InlineConst);
|
||||
ExprKind::ConstBlock(ref expr) => {
|
||||
self.resolve_anon_const_manual(false, AnonConstKind::InlineConst, |this| {
|
||||
this.visit_expr(expr)
|
||||
});
|
||||
}
|
||||
ExprKind::Index(ref elem, ref idx, _) => {
|
||||
self.resolve_expr(elem, Some(expr));
|
||||
|
@ -32,7 +32,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::sync::{FreezeReadGuard, Lrc};
|
||||
use rustc_errors::{Applicability, Diag, ErrCode};
|
||||
use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed};
|
||||
use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
|
||||
use rustc_feature::BUILTIN_ATTRIBUTES;
|
||||
use rustc_hir::def::Namespace::{self, *};
|
||||
@ -1048,6 +1048,7 @@ pub struct Resolver<'a, 'tcx> {
|
||||
|
||||
/// Maps glob imports to the names of items actually imported.
|
||||
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
|
||||
glob_error: Option<ErrorGuaranteed>,
|
||||
visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
|
||||
used_imports: FxHashSet<NodeId>,
|
||||
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
|
||||
@ -1417,6 +1418,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
ast_transform_scopes: FxHashMap::default(),
|
||||
|
||||
glob_map: Default::default(),
|
||||
glob_error: None,
|
||||
visibilities_for_hashing: Default::default(),
|
||||
used_imports: FxHashSet::default(),
|
||||
maybe_unused_trait_imports: Default::default(),
|
||||
|
@ -159,7 +159,23 @@ pub enum CoverageLevel {
|
||||
Block,
|
||||
/// Also instrument branch points (includes block coverage).
|
||||
Branch,
|
||||
/// Instrument for MC/DC. Mostly a superset of branch coverage, but might
|
||||
/// Same as branch coverage, but also adds branch instrumentation for
|
||||
/// certain boolean expressions that are not directly used for branching.
|
||||
///
|
||||
/// For example, in the following code, `b` does not directly participate
|
||||
/// in a branch, but condition coverage will instrument it as its own
|
||||
/// artificial branch:
|
||||
/// ```
|
||||
/// # let (a, b) = (false, true);
|
||||
/// let x = a && b;
|
||||
/// // ^ last operand
|
||||
/// ```
|
||||
///
|
||||
/// This level is mainly intended to be a stepping-stone towards full MC/DC
|
||||
/// instrumentation, so it might be removed in the future when MC/DC is
|
||||
/// sufficiently complete, or if it is making MC/DC changes difficult.
|
||||
Condition,
|
||||
/// Instrument for MC/DC. Mostly a superset of condition coverage, but might
|
||||
/// differ in some corner cases.
|
||||
Mcdc,
|
||||
}
|
||||
@ -773,6 +789,7 @@ pub enum PrintKind {
|
||||
TargetLibdir,
|
||||
CrateName,
|
||||
Cfg,
|
||||
CheckCfg,
|
||||
CallingConventions,
|
||||
TargetList,
|
||||
TargetCPUs,
|
||||
@ -1443,7 +1460,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
|
||||
"",
|
||||
"print",
|
||||
"Compiler information to print on stdout",
|
||||
"[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
|
||||
"[crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|\
|
||||
target-list|target-cpus|target-features|relocation-models|code-models|\
|
||||
tls-models|target-spec-json|all-target-specs-json|native-static-libs|\
|
||||
stack-protector-strategies|link-args|deployment-target]",
|
||||
@ -1859,6 +1876,7 @@ fn collect_print_requests(
|
||||
("all-target-specs-json", PrintKind::AllTargetSpecs),
|
||||
("calling-conventions", PrintKind::CallingConventions),
|
||||
("cfg", PrintKind::Cfg),
|
||||
("check-cfg", PrintKind::CheckCfg),
|
||||
("code-models", PrintKind::CodeModels),
|
||||
("crate-name", PrintKind::CrateName),
|
||||
("deployment-target", PrintKind::DeploymentTarget),
|
||||
@ -1908,6 +1926,16 @@ fn collect_print_requests(
|
||||
);
|
||||
}
|
||||
}
|
||||
Some((_, PrintKind::CheckCfg)) => {
|
||||
if unstable_opts.unstable_options {
|
||||
PrintKind::CheckCfg
|
||||
} else {
|
||||
early_dcx.early_fatal(
|
||||
"the `-Z unstable-options` flag must also be passed to \
|
||||
enable the check-cfg print option",
|
||||
);
|
||||
}
|
||||
}
|
||||
Some(&(_, print_kind)) => print_kind,
|
||||
None => {
|
||||
let prints =
|
||||
|
@ -395,7 +395,7 @@ mod desc {
|
||||
pub const parse_optimization_fuel: &str = "crate=integer";
|
||||
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
|
||||
pub const parse_instrument_coverage: &str = parse_bool;
|
||||
pub const parse_coverage_options: &str = "`block` | `branch` | `mcdc`";
|
||||
pub const parse_coverage_options: &str = "`block` | `branch` | `condition` | `mcdc`";
|
||||
pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`";
|
||||
pub const parse_unpretty: &str = "`string` or `string=string`";
|
||||
pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
|
||||
@ -961,6 +961,7 @@ mod parse {
|
||||
match option {
|
||||
"block" => slot.level = CoverageLevel::Block,
|
||||
"branch" => slot.level = CoverageLevel::Branch,
|
||||
"condition" => slot.level = CoverageLevel::Condition,
|
||||
"mcdc" => slot.level = CoverageLevel::Mcdc,
|
||||
_ => return false,
|
||||
}
|
||||
@ -1678,6 +1679,8 @@ options! {
|
||||
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
|
||||
(default: no)"),
|
||||
fixed_x18: bool = (false, parse_bool, [TRACKED],
|
||||
"make the x18 register reserved on AArch64 (default: no)"),
|
||||
flatten_format_args: bool = (true, parse_bool, [TRACKED],
|
||||
"flatten nested format_args!() and literals into a simplified format_args!() call \
|
||||
(default: yes)"),
|
||||
|
@ -353,6 +353,11 @@ impl Session {
|
||||
&& self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Branch
|
||||
}
|
||||
|
||||
pub fn instrument_coverage_condition(&self) -> bool {
|
||||
self.instrument_coverage()
|
||||
&& self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Condition
|
||||
}
|
||||
|
||||
pub fn instrument_coverage_mcdc(&self) -> bool {
|
||||
self.instrument_coverage()
|
||||
&& self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc
|
||||
|
@ -10,7 +10,7 @@ use rustc_span::Symbol;
|
||||
use stable_mir::abi::Layout;
|
||||
use stable_mir::mir::alloc::AllocId;
|
||||
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
|
||||
use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety};
|
||||
use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety, UnOp};
|
||||
use stable_mir::ty::{
|
||||
Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
|
||||
DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
|
||||
@ -582,6 +582,18 @@ impl RustcInternal for BinOp {
|
||||
}
|
||||
}
|
||||
|
||||
impl RustcInternal for UnOp {
|
||||
type T<'tcx> = rustc_middle::mir::UnOp;
|
||||
|
||||
fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
||||
match self {
|
||||
UnOp::Not => rustc_middle::mir::UnOp::Not,
|
||||
UnOp::Neg => rustc_middle::mir::UnOp::Neg,
|
||||
UnOp::PtrMetadata => rustc_middle::mir::UnOp::PtrMetadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RustcInternal for &T
|
||||
where
|
||||
T: RustcInternal,
|
||||
|
@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape};
|
||||
use stable_mir::compiler_interface::Context;
|
||||
use stable_mir::mir::alloc::GlobalAlloc;
|
||||
use stable_mir::mir::mono::{InstanceDef, StaticDef};
|
||||
use stable_mir::mir::{BinOp, Body, Place};
|
||||
use stable_mir::mir::{BinOp, Body, Place, UnOp};
|
||||
use stable_mir::target::{MachineInfo, MachineSize};
|
||||
use stable_mir::ty::{
|
||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
||||
@ -700,6 +700,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||
let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal);
|
||||
ty.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let arg_internal = arg.internal(&mut *tables, tcx);
|
||||
let ty = un_op.internal(&mut *tables, tcx).ty(tcx, arg_internal);
|
||||
ty.stable(&mut *tables)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
|
||||
|
@ -526,6 +526,7 @@ impl<'tcx> Stable<'tcx> for mir::UnOp {
|
||||
match self {
|
||||
UnOp::Not => stable_mir::mir::UnOp::Not,
|
||||
UnOp::Neg => stable_mir::mir::UnOp::Neg,
|
||||
UnOp::PtrMetadata => stable_mir::mir::UnOp::PtrMetadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +210,6 @@ symbols! {
|
||||
FsPermissions,
|
||||
FusedIterator,
|
||||
Future,
|
||||
FutureOutput,
|
||||
GlobalAlloc,
|
||||
Hash,
|
||||
HashMap,
|
||||
@ -439,8 +438,10 @@ symbols! {
|
||||
async_fn,
|
||||
async_fn_in_trait,
|
||||
async_fn_kind_helper,
|
||||
async_fn_kind_upvars,
|
||||
async_fn_mut,
|
||||
async_fn_once,
|
||||
async_fn_once_output,
|
||||
async_fn_track_caller,
|
||||
async_fn_traits,
|
||||
async_for_loop,
|
||||
@ -498,6 +499,8 @@ symbols! {
|
||||
call,
|
||||
call_mut,
|
||||
call_once,
|
||||
call_once_future,
|
||||
call_ref_future,
|
||||
caller_location,
|
||||
capture_disjoint_fields,
|
||||
catch_unwind,
|
||||
@ -911,6 +914,7 @@ symbols! {
|
||||
fundamental,
|
||||
fused_iterator,
|
||||
future,
|
||||
future_output,
|
||||
future_trait,
|
||||
gdb_script_file,
|
||||
ge,
|
||||
@ -1179,6 +1183,7 @@ symbols! {
|
||||
mir_make_place,
|
||||
mir_move,
|
||||
mir_offset,
|
||||
mir_ptr_metadata,
|
||||
mir_retag,
|
||||
mir_return,
|
||||
mir_return_to,
|
||||
@ -1433,6 +1438,7 @@ symbols! {
|
||||
ptr_guaranteed_cmp,
|
||||
ptr_is_null,
|
||||
ptr_mask,
|
||||
ptr_metadata,
|
||||
ptr_null,
|
||||
ptr_null_mut,
|
||||
ptr_offset_from,
|
||||
|
@ -11,11 +11,10 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 {
|
||||
arg.make_indirect();
|
||||
} else {
|
||||
// FIXME: this is wrong! Need to decide which ABI we really want here.
|
||||
arg.make_direct_deprecated();
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.make_indirect_byval(None);
|
||||
} else if arg.layout.size.bits() < 32 {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
let tcx = self.interner();
|
||||
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
|
||||
debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some());
|
||||
|
||||
// Structurally normalize the lhs.
|
||||
let lhs = if let Some(alias) = lhs.to_alias_term() {
|
||||
|
@ -83,7 +83,7 @@ pub(super) trait GoalKind<'tcx>:
|
||||
assumption: ty::Clause<'tcx>,
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
|
||||
let tcx = ecx.tcx();
|
||||
let tcx = ecx.interner();
|
||||
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
|
||||
bug!("expected object type in `probe_and_consider_object_bound_candidate`");
|
||||
};
|
||||
@ -288,8 +288,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
|
||||
}
|
||||
|
||||
let goal: Goal<'tcx, G> =
|
||||
goal.with(self.tcx(), goal.predicate.with_self_ty(self.tcx(), normalized_self_ty));
|
||||
let goal: Goal<'tcx, G> = goal.with(
|
||||
self.interner(),
|
||||
goal.predicate.with_self_ty(self.interner(), normalized_self_ty),
|
||||
);
|
||||
// Vars that show up in the rest of the goal substs may have been constrained by
|
||||
// normalizing the self type as well, since type variables are not uniquified.
|
||||
let goal = self.resolve_vars_if_possible(goal);
|
||||
@ -339,7 +341,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
let tcx = self.interner();
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
|
||||
let mut consider_impls_for_simplified_type = |simp| {
|
||||
@ -455,7 +457,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
let tcx = self.interner();
|
||||
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
|
||||
for &impl_def_id in trait_impls.blanket_impls() {
|
||||
// For every `default impl`, there's always a non-default `impl`
|
||||
@ -478,7 +480,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
let tcx = self.interner();
|
||||
let lang_items = tcx.lang_items();
|
||||
let trait_def_id = goal.predicate.trait_def_id(tcx);
|
||||
|
||||
@ -505,9 +507,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
G::consider_builtin_pointer_like_candidate(self, goal)
|
||||
} else if lang_items.fn_ptr_trait() == Some(trait_def_id) {
|
||||
G::consider_builtin_fn_ptr_trait_candidate(self, goal)
|
||||
} else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) {
|
||||
} else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) {
|
||||
G::consider_builtin_fn_trait_candidates(self, goal, kind)
|
||||
} else if let Some(kind) = self.tcx().async_fn_trait_kind_from_def_id(trait_def_id) {
|
||||
} else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) {
|
||||
G::consider_builtin_async_fn_trait_candidates(self, goal, kind)
|
||||
} else if lang_items.async_fn_kind_helper() == Some(trait_def_id) {
|
||||
G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
|
||||
@ -634,7 +636,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
|
||||
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
|
||||
ty::Alias(ty::Inherent | ty::Weak, _) => {
|
||||
self.tcx().sess.dcx().span_delayed_bug(
|
||||
self.interner().sess.dcx().span_delayed_bug(
|
||||
DUMMY_SP,
|
||||
format!("could not normalize {self_ty}, it is not WF"),
|
||||
);
|
||||
@ -643,7 +645,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
};
|
||||
|
||||
for assumption in
|
||||
self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
|
||||
self.interner().item_bounds(alias_ty.def_id).instantiate(self.interner(), alias_ty.args)
|
||||
{
|
||||
candidates.extend(G::probe_and_consider_implied_clause(
|
||||
self,
|
||||
@ -673,7 +675,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
let tcx = self.interner();
|
||||
if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object {
|
||||
return;
|
||||
}
|
||||
@ -764,7 +766,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
let tcx = self.interner();
|
||||
|
||||
candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
|
||||
|ecx| {
|
||||
@ -793,7 +795,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
let tcx = self.interner();
|
||||
let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
|
||||
goal.with(tcx, goal.predicate.trait_ref(tcx));
|
||||
|
||||
|
@ -9,7 +9,6 @@ use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::traits::solve::Goal;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast};
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::solve::EvalCtxt;
|
||||
|
||||
@ -22,7 +21,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||
ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
|
||||
let tcx = ecx.tcx();
|
||||
let tcx = ecx.interner();
|
||||
match *ty.kind() {
|
||||
ty::Uint(_)
|
||||
| ty::Int(_)
|
||||
@ -75,7 +74,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||
}
|
||||
|
||||
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
||||
.tcx()
|
||||
.interner()
|
||||
.bound_coroutine_hidden_types(def_id)
|
||||
.map(|bty| bty.instantiate(tcx, args))
|
||||
.collect()),
|
||||
@ -151,8 +150,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||
// "best effort" optimization and `sized_constraint` may return `Some`, even
|
||||
// if the ADT is sized for all possible args.
|
||||
ty::Adt(def, args) => {
|
||||
if let Some(sized_crit) = def.sized_constraint(ecx.tcx()) {
|
||||
Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.tcx(), args))])
|
||||
if let Some(sized_crit) = def.sized_constraint(ecx.interner()) {
|
||||
Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), args))])
|
||||
} else {
|
||||
Ok(vec![])
|
||||
}
|
||||
@ -210,10 +209,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||
|
||||
// only when `coroutine_clone` is enabled and the coroutine is movable
|
||||
// impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses)
|
||||
ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) {
|
||||
ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) {
|
||||
Movability::Static => Err(NoSolution),
|
||||
Movability::Movable => {
|
||||
if ecx.tcx().features().coroutine_clone {
|
||||
if ecx.interner().features().coroutine_clone {
|
||||
let coroutine = args.as_coroutine();
|
||||
Ok(vec![
|
||||
ty::Binder::dummy(coroutine.tupled_upvars_ty()),
|
||||
@ -227,9 +226,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||
|
||||
// impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
|
||||
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
||||
.tcx()
|
||||
.interner()
|
||||
.bound_coroutine_hidden_types(def_id)
|
||||
.map(|bty| bty.instantiate(ecx.tcx(), args))
|
||||
.map(|bty| bty.instantiate(ecx.interner(), args))
|
||||
.collect()),
|
||||
}
|
||||
}
|
||||
@ -454,12 +453,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
||||
.rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]))
|
||||
.upcast(tcx),
|
||||
];
|
||||
let future_output_def_id = tcx
|
||||
.associated_items(future_trait_def_id)
|
||||
.filter_by_name_unhygienic(sym::Output)
|
||||
.next()
|
||||
.unwrap()
|
||||
.def_id;
|
||||
let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None);
|
||||
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
|
||||
Ok((
|
||||
bound_sig.rebind(AsyncCallableRelevantTypes {
|
||||
@ -510,12 +504,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
||||
);
|
||||
}
|
||||
|
||||
let future_output_def_id = tcx
|
||||
.associated_items(future_trait_def_id)
|
||||
.filter_by_name_unhygienic(sym::Output)
|
||||
.next()
|
||||
.unwrap()
|
||||
.def_id;
|
||||
let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None);
|
||||
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
|
||||
Ok((
|
||||
bound_sig.rebind(AsyncCallableRelevantTypes {
|
||||
@ -592,13 +581,7 @@ fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
|
||||
args: ty::CoroutineClosureArgs<'tcx>,
|
||||
sig: ty::CoroutineClosureSignature<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let async_fn_kind_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
||||
let upvars_projection_def_id = tcx
|
||||
.associated_items(async_fn_kind_trait_def_id)
|
||||
.filter_by_name_unhygienic(sym::Upvars)
|
||||
.next()
|
||||
.unwrap()
|
||||
.def_id;
|
||||
let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None);
|
||||
let tupled_upvars_ty = Ty::new_projection(
|
||||
tcx,
|
||||
upvars_projection_def_id,
|
||||
@ -666,7 +649,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> {
|
||||
let tcx = ecx.tcx();
|
||||
let tcx = ecx.interner();
|
||||
let mut requirements = vec![];
|
||||
requirements.extend(
|
||||
tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.args).predicates,
|
||||
@ -722,7 +705,7 @@ struct ReplaceProjectionWith<'a, 'tcx> {
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.ecx.tcx()
|
||||
self.ecx.interner()
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
@ -739,7 +722,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
|
||||
.eq_and_get_goals(
|
||||
self.param_env,
|
||||
alias_ty,
|
||||
proj.projection_term.expect_ty(self.ecx.tcx()),
|
||||
proj.projection_term.expect_ty(self.ecx.interner()),
|
||||
)
|
||||
.expect("expected to be able to unify goal projection with dyn's projection"),
|
||||
);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user