Merge from rustc
This commit is contained in:
commit
aa74d61665
374 changed files with 3634 additions and 2231 deletions
|
@ -4234,6 +4234,7 @@ name = "rustc_monomorphize"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
@ -4243,6 +4244,7 @@ dependencies = [
|
|||
"rustc_middle",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_symbol_mangling",
|
||||
"rustc_target",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
@ -79,6 +79,7 @@ pub struct AutoDiffItem {
|
|||
pub target: String,
|
||||
pub attrs: AutoDiffAttrs,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct AutoDiffAttrs {
|
||||
/// Conceptually either forward or reverse mode AD, as described in various autodiff papers and
|
||||
|
@ -231,7 +232,7 @@ impl AutoDiffAttrs {
|
|||
self.ret_activity == DiffActivity::ActiveOnly
|
||||
}
|
||||
|
||||
pub fn error() -> Self {
|
||||
pub const fn error() -> Self {
|
||||
AutoDiffAttrs {
|
||||
mode: DiffMode::Error,
|
||||
ret_activity: DiffActivity::None,
|
||||
|
|
|
@ -3777,7 +3777,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let tcx = self.infcx.tcx;
|
||||
if let Some(Terminator { kind: TerminatorKind::Call { call_source, fn_span, .. }, .. }) =
|
||||
&self.body[loan.reserve_location.block].terminator
|
||||
&& let Some((method_did, method_args)) = rustc_middle::util::find_self_call(
|
||||
&& let Some((method_did, method_args)) = mir::find_self_call(
|
||||
tcx,
|
||||
self.body,
|
||||
loan.assigned_place.local,
|
||||
|
|
|
@ -17,7 +17,7 @@ use rustc_middle::mir::tcx::PlaceTy;
|
|||
use rustc_middle::mir::{
|
||||
AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
|
||||
LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement,
|
||||
StatementKind, Terminator, TerminatorKind,
|
||||
StatementKind, Terminator, TerminatorKind, find_self_call,
|
||||
};
|
||||
use rustc_middle::ty::print::Print;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
@ -1016,12 +1016,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
kind: TerminatorKind::Call { fn_span, call_source, .. }, ..
|
||||
}) = &self.body[location.block].terminator
|
||||
{
|
||||
let Some((method_did, method_args)) = rustc_middle::util::find_self_call(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
target_temp,
|
||||
location.block,
|
||||
) else {
|
||||
let Some((method_did, method_args)) =
|
||||
find_self_call(self.infcx.tcx, self.body, target_temp, location.block)
|
||||
else {
|
||||
return normal_ret;
|
||||
};
|
||||
|
||||
|
|
|
@ -417,6 +417,16 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
Some(source_info.span),
|
||||
);
|
||||
}
|
||||
AssertKind::NullPointerDereference => {
|
||||
let location = fx.get_caller_location(source_info).load_scalar(fx);
|
||||
|
||||
codegen_panic_inner(
|
||||
fx,
|
||||
rustc_hir::LangItem::PanicNullPointerDereference,
|
||||
&[location],
|
||||
Some(source_info.span),
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let location = fx.get_caller_location(source_info).load_scalar(fx);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use cranelift_module::*;
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::interpret::{AllocId, GlobalAlloc, Scalar, read_target_uint};
|
||||
use rustc_middle::ty::{Binder, ExistentialTraitRef, ScalarInt};
|
||||
use rustc_middle::ty::{ExistentialTraitRef, ScalarInt};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
|
@ -167,7 +167,9 @@ pub(crate) fn codegen_const_value<'tcx>(
|
|||
&mut fx.constants_cx,
|
||||
fx.module,
|
||||
ty,
|
||||
dyn_ty.principal(),
|
||||
dyn_ty.principal().map(|principal| {
|
||||
fx.tcx.instantiate_bound_regions_with_erased(principal)
|
||||
}),
|
||||
);
|
||||
let local_data_id =
|
||||
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
|
||||
|
@ -243,7 +245,7 @@ pub(crate) fn data_id_for_vtable<'tcx>(
|
|||
cx: &mut ConstantCx,
|
||||
module: &mut dyn Module,
|
||||
ty: Ty<'tcx>,
|
||||
trait_ref: Option<Binder<'tcx, ExistentialTraitRef<'tcx>>>,
|
||||
trait_ref: Option<ExistentialTraitRef<'tcx>>,
|
||||
) -> DataId {
|
||||
let alloc_id = tcx.vtable_allocation((ty, trait_ref));
|
||||
data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not)
|
||||
|
@ -460,9 +462,15 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
|||
GlobalAlloc::Memory(target_alloc) => {
|
||||
data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability)
|
||||
}
|
||||
GlobalAlloc::VTable(ty, dyn_ty) => {
|
||||
data_id_for_vtable(tcx, cx, module, ty, dyn_ty.principal())
|
||||
}
|
||||
GlobalAlloc::VTable(ty, dyn_ty) => data_id_for_vtable(
|
||||
tcx,
|
||||
cx,
|
||||
module,
|
||||
ty,
|
||||
dyn_ty
|
||||
.principal()
|
||||
.map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
|
||||
),
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
|
||||
{
|
||||
|
|
|
@ -61,7 +61,12 @@ pub(crate) fn unsized_info<'tcx>(
|
|||
old_info
|
||||
}
|
||||
}
|
||||
(_, ty::Dynamic(data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()),
|
||||
(_, ty::Dynamic(data, ..)) => crate::vtable::get_vtable(
|
||||
fx,
|
||||
source,
|
||||
data.principal()
|
||||
.map(|principal| fx.tcx.instantiate_bound_regions_with_erased(principal)),
|
||||
),
|
||||
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
|
|||
pub(crate) fn get_vtable<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
|
||||
) -> Value {
|
||||
let data_id = data_id_for_vtable(fx.tcx, &mut fx.constants_cx, fx.module, ty, trait_ref);
|
||||
let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func);
|
||||
|
|
|
@ -234,7 +234,12 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
GlobalAlloc::VTable(ty, dyn_ty) => {
|
||||
let alloc = self
|
||||
.tcx
|
||||
.global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
|
||||
.global_alloc(self.tcx.vtable_allocation((
|
||||
ty,
|
||||
dyn_ty.principal().map(|principal| {
|
||||
self.tcx.instantiate_bound_regions_with_erased(principal)
|
||||
}),
|
||||
)))
|
||||
.unwrap_memory();
|
||||
let init = const_alloc_to_gcc(self, alloc);
|
||||
self.static_addr_of(init, alloc.inner().align, None)
|
||||
|
|
|
@ -14,7 +14,7 @@ use rustc_middle::ty::layout::{
|
|||
FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError,
|
||||
LayoutOfHelpers,
|
||||
};
|
||||
use rustc_middle::ty::{self, Instance, PolyExistentialTraitRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::respan;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
|
@ -90,7 +90,7 @@ pub struct CodegenCx<'gcc, 'tcx> {
|
|||
pub function_instances: RefCell<FxHashMap<Instance<'tcx>, Function<'gcc>>>,
|
||||
/// Cache generated vtables
|
||||
pub vtables:
|
||||
RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
|
||||
RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
|
||||
|
||||
// TODO(antoyo): improve the SSA API to not require those.
|
||||
/// Mapping from function pointer type to indexes of on stack parameters.
|
||||
|
@ -401,7 +401,7 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
|
|||
impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
fn vtables(
|
||||
&self,
|
||||
) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
|
||||
) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
|
||||
&self.vtables
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc_data_structures::sync::Lrc;
|
|||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::mir::{self, Body, SourceScope};
|
||||
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
|
||||
use rustc_middle::ty::{ExistentialTraitRef, Instance, Ty};
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol};
|
||||
use rustc_target::abi::Size;
|
||||
|
@ -214,7 +214,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
fn create_vtable_debuginfo(
|
||||
&self,
|
||||
_ty: Ty<'tcx>,
|
||||
_trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
|
||||
_trait_ref: Option<ExistentialTraitRef<'tcx>>,
|
||||
_vtable: Self::Value,
|
||||
) {
|
||||
// TODO(antoyo)
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
// Run-time:
|
||||
// status: 0
|
||||
|
||||
#![feature(const_black_box)]
|
||||
|
||||
/*
|
||||
* Code
|
||||
*/
|
||||
|
|
|
@ -62,8 +62,8 @@ fn generate_enzyme_call<'ll>(
|
|||
// add outer_fn name to ad_name to make it unique, in case users apply autodiff to multiple
|
||||
// functions. Unwrap will only panic, if LLVM gave us an invalid string.
|
||||
let name = llvm::get_value_name(outer_fn);
|
||||
let outer_fn_name = std::ffi::CStr::from_bytes_with_nul(name).unwrap().to_str().unwrap();
|
||||
ad_name.push_str(outer_fn_name.to_string().as_str());
|
||||
let outer_fn_name = std::str::from_utf8(name).unwrap();
|
||||
ad_name.push_str(outer_fn_name);
|
||||
|
||||
// Let us assume the user wrote the following function square:
|
||||
//
|
||||
|
@ -255,14 +255,14 @@ fn generate_enzyme_call<'ll>(
|
|||
// have no debug info to copy, which would then be ok.
|
||||
trace!("no dbg info");
|
||||
}
|
||||
// Now that we copied the metadata, get rid of dummy code.
|
||||
llvm::LLVMRustEraseInstBefore(entry, last_inst);
|
||||
llvm::LLVMRustEraseInstFromParent(last_inst);
|
||||
|
||||
if cx.val_ty(outer_fn) != cx.type_void() {
|
||||
builder.ret(call);
|
||||
} else {
|
||||
// Now that we copied the metadata, get rid of dummy code.
|
||||
llvm::LLVMRustEraseInstUntilInclusive(entry, last_inst);
|
||||
|
||||
if cx.val_ty(call) == cx.type_void() {
|
||||
builder.ret_void();
|
||||
} else {
|
||||
builder.ret(call);
|
||||
}
|
||||
|
||||
// Let's crash in case that we messed something up above and generated invalid IR.
|
||||
|
|
|
@ -314,7 +314,12 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
GlobalAlloc::VTable(ty, dyn_ty) => {
|
||||
let alloc = self
|
||||
.tcx
|
||||
.global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
|
||||
.global_alloc(self.tcx.vtable_allocation((
|
||||
ty,
|
||||
dyn_ty.principal().map(|principal| {
|
||||
self.tcx.instantiate_bound_regions_with_erased(principal)
|
||||
}),
|
||||
)))
|
||||
.unwrap_memory();
|
||||
let init = const_alloc_to_llvm(self, alloc, /*static*/ false);
|
||||
let value = self.static_addr_of_impl(init, alloc.inner().align, None);
|
||||
|
|
|
@ -77,8 +77,7 @@ pub(crate) struct CodegenCx<'ll, 'tcx> {
|
|||
/// Cache instances of monomorphic and polymorphic items
|
||||
pub instances: RefCell<FxHashMap<Instance<'tcx>, &'ll Value>>,
|
||||
/// Cache generated vtables
|
||||
pub vtables:
|
||||
RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>,
|
||||
pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), &'ll Value>>,
|
||||
/// Cache of constant strings,
|
||||
pub const_str_cache: RefCell<FxHashMap<String, &'ll Value>>,
|
||||
|
||||
|
@ -663,15 +662,14 @@ impl<'ll> SimpleCx<'ll> {
|
|||
impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
fn vtables(
|
||||
&self,
|
||||
) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>
|
||||
{
|
||||
) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), &'ll Value>> {
|
||||
&self.vtables
|
||||
}
|
||||
|
||||
fn apply_vcall_visibility_metadata(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
|
||||
vtable: &'ll Value,
|
||||
) {
|
||||
apply_vcall_visibility_metadata(self, ty, poly_trait_ref, vtable);
|
||||
|
|
|
@ -298,7 +298,7 @@ struct UsageSets<'tcx> {
|
|||
/// Prepare sets of definitions that are relevant to deciding whether something
|
||||
/// is an "unused function" for coverage purposes.
|
||||
fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
|
||||
let MonoItemPartitions { all_mono_items, codegen_units } =
|
||||
let MonoItemPartitions { all_mono_items, codegen_units, .. } =
|
||||
tcx.collect_and_partition_mono_items(());
|
||||
|
||||
// Obtain a MIR body for each function participating in codegen, via an
|
||||
|
|
|
@ -13,7 +13,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, CoroutineArgsExt, Instance, PolyExistentialTraitRef, Ty, TyCtxt, Visibility,
|
||||
self, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility,
|
||||
};
|
||||
use rustc_session::config::{self, DebugInfo, Lto};
|
||||
use rustc_span::{DUMMY_SP, FileName, FileNameDisplayPreference, SourceFile, Symbol, hygiene};
|
||||
|
@ -1399,7 +1399,7 @@ pub(crate) fn build_global_var_di_node<'ll>(
|
|||
fn build_vtable_type_di_node<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
|
||||
) -> &'ll DIType {
|
||||
let tcx = cx.tcx;
|
||||
|
||||
|
@ -1510,7 +1510,7 @@ fn find_vtable_behind_cast<'ll>(vtable: &'ll Value) -> &'ll Value {
|
|||
pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
|
||||
trait_ref: Option<ExistentialTraitRef<'tcx>>,
|
||||
vtable: &'ll Value,
|
||||
) {
|
||||
// FIXME(flip1995): The virtual function elimination optimization only works with full LTO in
|
||||
|
@ -1531,7 +1531,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
|
|||
let vtable = find_vtable_behind_cast(vtable);
|
||||
let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
|
||||
let trait_ref_self = cx.tcx.erase_regions(trait_ref_self);
|
||||
let trait_def_id = trait_ref_self.def_id();
|
||||
let trait_def_id = trait_ref_self.def_id;
|
||||
let trait_vis = cx.tcx.visibility(trait_def_id);
|
||||
|
||||
let cgus = cx.sess().codegen_units().as_usize();
|
||||
|
@ -1590,7 +1590,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
|
|||
pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
|
||||
vtable: &'ll Value,
|
||||
) {
|
||||
if cx.dbg_cx.is_none() {
|
||||
|
|
|
@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{self, PolyExistentialTraitRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, ExistentialTraitRef, Ty, TyCtxt};
|
||||
|
||||
use super::{DefinitionLocation, SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata};
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
|
@ -44,7 +44,7 @@ pub(super) enum UniqueTypeId<'tcx> {
|
|||
/// The ID for the additional wrapper struct type describing an enum variant in CPP-like mode.
|
||||
VariantStructTypeCppLikeWrapper(Ty<'tcx>, VariantIdx, private::HiddenZst),
|
||||
/// The ID of the artificial type we create for VTables.
|
||||
VTableTy(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>, private::HiddenZst),
|
||||
VTableTy(Ty<'tcx>, Option<ExistentialTraitRef<'tcx>>, private::HiddenZst),
|
||||
}
|
||||
|
||||
impl<'tcx> UniqueTypeId<'tcx> {
|
||||
|
@ -88,7 +88,7 @@ impl<'tcx> UniqueTypeId<'tcx> {
|
|||
pub(crate) fn for_vtable_ty(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_type: Ty<'tcx>,
|
||||
implemented_trait: Option<PolyExistentialTraitRef<'tcx>>,
|
||||
implemented_trait: Option<ExistentialTraitRef<'tcx>>,
|
||||
) -> Self {
|
||||
assert_eq!(
|
||||
self_type,
|
||||
|
|
|
@ -588,7 +588,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
fn create_vtable_debuginfo(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
|
||||
vtable: Self::Value,
|
||||
) {
|
||||
metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
|
||||
|
|
|
@ -7,11 +7,13 @@ use crate::llvm::Bool;
|
|||
extern "C" {
|
||||
// Enzyme
|
||||
pub fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool;
|
||||
pub fn LLVMRustEraseInstBefore(BB: &BasicBlock, I: &Value);
|
||||
pub fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value);
|
||||
pub fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>;
|
||||
pub fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
|
||||
pub fn LLVMRustEraseInstFromParent(V: &Value);
|
||||
pub fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value;
|
||||
pub fn LLVMDumpModule(M: &Module);
|
||||
pub fn LLVMDumpValue(V: &Value);
|
||||
pub fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
|
||||
|
||||
pub fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
|
||||
|
|
|
@ -16,6 +16,8 @@ codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$erro
|
|||
|
||||
codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
|
||||
|
||||
codegen_ssa_autodiff_without_lto = using the autodiff feature requires using fat-lto
|
||||
|
||||
codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty
|
||||
|
||||
codegen_ssa_cgu_not_recorded =
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::sync::mpsc::{Receiver, Sender, channel};
|
|||
use std::{fs, io, mem, str, thread};
|
||||
|
||||
use rustc_ast::attr;
|
||||
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::jobserver::{self, Acquired};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
|
@ -40,7 +41,7 @@ use tracing::debug;
|
|||
use super::link::{self, ensure_removed};
|
||||
use super::lto::{self, SerializedModule};
|
||||
use super::symbol_export::symbol_name_for_instance_in_crate;
|
||||
use crate::errors::ErrorCreatingRemarkDir;
|
||||
use crate::errors::{AutodiffWithoutLto, ErrorCreatingRemarkDir};
|
||||
use crate::traits::*;
|
||||
use crate::{
|
||||
CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
|
||||
|
@ -118,6 +119,7 @@ pub struct ModuleConfig {
|
|||
pub merge_functions: bool,
|
||||
pub emit_lifetime_markers: bool,
|
||||
pub llvm_plugins: Vec<String>,
|
||||
pub autodiff: Vec<config::AutoDiff>,
|
||||
}
|
||||
|
||||
impl ModuleConfig {
|
||||
|
@ -266,6 +268,7 @@ impl ModuleConfig {
|
|||
|
||||
emit_lifetime_markers: sess.emit_lifetime_markers(),
|
||||
llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]),
|
||||
autodiff: if_regular!(sess.opts.unstable_opts.autodiff.clone(), vec![]),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,6 +392,7 @@ impl<B: WriteBackendMethods> CodegenContext<B> {
|
|||
|
||||
fn generate_lto_work<B: ExtraBackendMethods>(
|
||||
cgcx: &CodegenContext<B>,
|
||||
autodiff: Vec<AutoDiffItem>,
|
||||
needs_fat_lto: Vec<FatLtoInput<B>>,
|
||||
needs_thin_lto: Vec<(String, B::ThinBuffer)>,
|
||||
import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>,
|
||||
|
@ -397,11 +401,19 @@ fn generate_lto_work<B: ExtraBackendMethods>(
|
|||
|
||||
if !needs_fat_lto.is_empty() {
|
||||
assert!(needs_thin_lto.is_empty());
|
||||
let module =
|
||||
let mut module =
|
||||
B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise());
|
||||
if cgcx.lto == Lto::Fat {
|
||||
let config = cgcx.config(ModuleKind::Regular);
|
||||
module = unsafe { module.autodiff(cgcx, autodiff, config).unwrap() };
|
||||
}
|
||||
// We are adding a single work item, so the cost doesn't matter.
|
||||
vec![(WorkItem::LTO(module), 0)]
|
||||
} else {
|
||||
if !autodiff.is_empty() {
|
||||
let dcx = cgcx.create_dcx();
|
||||
dcx.handle().emit_fatal(AutodiffWithoutLto {});
|
||||
}
|
||||
assert!(needs_fat_lto.is_empty());
|
||||
let (lto_modules, copy_jobs) = B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules)
|
||||
.unwrap_or_else(|e| e.raise());
|
||||
|
@ -1021,6 +1033,9 @@ pub(crate) enum Message<B: WriteBackendMethods> {
|
|||
/// Sent from a backend worker thread.
|
||||
WorkItem { result: Result<WorkItemResult<B>, Option<WorkerFatalError>>, worker_id: usize },
|
||||
|
||||
/// A vector containing all the AutoDiff tasks that we have to pass to Enzyme.
|
||||
AddAutoDiffItems(Vec<AutoDiffItem>),
|
||||
|
||||
/// The frontend has finished generating something (backend IR or a
|
||||
/// post-LTO artifact) for a codegen unit, and it should be passed to the
|
||||
/// backend. Sent from the main thread.
|
||||
|
@ -1348,6 +1363,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
|
||||
// This is where we collect codegen units that have gone all the way
|
||||
// through codegen and LLVM.
|
||||
let mut autodiff_items = Vec::new();
|
||||
let mut compiled_modules = vec![];
|
||||
let mut compiled_allocator_module = None;
|
||||
let mut needs_link = Vec::new();
|
||||
|
@ -1459,9 +1475,13 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
let needs_thin_lto = mem::take(&mut needs_thin_lto);
|
||||
let import_only_modules = mem::take(&mut lto_import_only_modules);
|
||||
|
||||
for (work, cost) in
|
||||
generate_lto_work(&cgcx, needs_fat_lto, needs_thin_lto, import_only_modules)
|
||||
{
|
||||
for (work, cost) in generate_lto_work(
|
||||
&cgcx,
|
||||
autodiff_items.clone(),
|
||||
needs_fat_lto,
|
||||
needs_thin_lto,
|
||||
import_only_modules,
|
||||
) {
|
||||
let insertion_index = work_items
|
||||
.binary_search_by_key(&cost, |&(_, cost)| cost)
|
||||
.unwrap_or_else(|e| e);
|
||||
|
@ -1596,6 +1616,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
main_thread_state = MainThreadState::Idle;
|
||||
}
|
||||
|
||||
Message::AddAutoDiffItems(mut items) => {
|
||||
autodiff_items.append(&mut items);
|
||||
}
|
||||
|
||||
Message::CodegenComplete => {
|
||||
if codegen_state != Aborted {
|
||||
codegen_state = Completed;
|
||||
|
@ -2070,6 +2094,10 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
|||
drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::<B>)));
|
||||
}
|
||||
|
||||
pub(crate) fn submit_autodiff_items(&self, items: Vec<AutoDiffItem>) {
|
||||
drop(self.coordinator.sender.send(Box::new(Message::<B>::AddAutoDiffItems(items))));
|
||||
}
|
||||
|
||||
pub(crate) fn check_for_errors(&self, sess: &Session) {
|
||||
self.shared_emitter_main.check(sess, false);
|
||||
}
|
||||
|
|
|
@ -18,14 +18,13 @@ use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, Debugger
|
|||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_middle::middle::{exported_symbols, lang_items};
|
||||
use rustc_middle::mir::BinOp;
|
||||
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
|
||||
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
|
||||
use rustc_span::{DUMMY_SP, Symbol, sym};
|
||||
use rustc_trait_selection::infer::at::ToTrace;
|
||||
use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
|
||||
use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
|
||||
use tracing::{debug, info};
|
||||
|
@ -129,14 +128,9 @@ pub fn validate_trivial_unsize<'tcx>(
|
|||
BoundRegionConversionTime::HigherRankedType,
|
||||
hr_source_principal,
|
||||
);
|
||||
let Ok(()) = ocx.eq_trace(
|
||||
let Ok(()) = ocx.eq(
|
||||
&ObligationCause::dummy(),
|
||||
param_env,
|
||||
ToTrace::to_trace(
|
||||
&ObligationCause::dummy(),
|
||||
hr_target_principal,
|
||||
hr_source_principal,
|
||||
),
|
||||
target_principal,
|
||||
source_principal,
|
||||
) else {
|
||||
|
@ -211,7 +205,12 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
old_info
|
||||
}
|
||||
}
|
||||
(_, ty::Dynamic(data, _, _)) => meth::get_vtable(cx, source, data.principal()),
|
||||
(_, ty::Dynamic(data, _, _)) => meth::get_vtable(
|
||||
cx,
|
||||
source,
|
||||
data.principal()
|
||||
.map(|principal| bx.tcx().instantiate_bound_regions_with_erased(principal)),
|
||||
),
|
||||
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
|
||||
}
|
||||
}
|
||||
|
@ -624,7 +623,9 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
|
||||
// Run the monomorphization collector and partition the collected items into
|
||||
// codegen units.
|
||||
let codegen_units = tcx.collect_and_partition_mono_items(()).codegen_units;
|
||||
let MonoItemPartitions { codegen_units, autodiff_items, .. } =
|
||||
tcx.collect_and_partition_mono_items(());
|
||||
let autodiff_fncs = autodiff_items.to_vec();
|
||||
|
||||
// Force all codegen_unit queries so they are already either red or green
|
||||
// when compile_codegen_unit accesses them. We are not able to re-execute
|
||||
|
@ -695,6 +696,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
);
|
||||
}
|
||||
|
||||
if !autodiff_fncs.is_empty() {
|
||||
ongoing_codegen.submit_autodiff_items(autodiff_fncs);
|
||||
}
|
||||
|
||||
// For better throughput during parallel processing by LLVM, we used to sort
|
||||
// CGUs largest to smallest. This would lead to better thread utilization
|
||||
// by, for example, preventing a large CGU from being processed last and
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use rustc_ast::attr::list_contains_name;
|
||||
use rustc_ast::{MetaItemInner, attr};
|
||||
use rustc_ast::expand::autodiff_attrs::{
|
||||
AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity,
|
||||
};
|
||||
use rustc_ast::{MetaItem, MetaItemInner, attr};
|
||||
use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::codes::*;
|
||||
|
@ -13,6 +18,7 @@ use rustc_middle::middle::codegen_fn_attrs::{
|
|||
};
|
||||
use rustc_middle::mir::mono::Linkage;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self as ty, TyCtxt};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::{Session, lint};
|
||||
|
@ -65,6 +71,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
|
||||
}
|
||||
|
||||
// If our rustc version supports autodiff/enzyme, then we call our handler
|
||||
// to check for any `#[rustc_autodiff(...)]` attributes.
|
||||
if cfg!(llvm_enzyme) {
|
||||
let ad = autodiff_attrs(tcx, did.into());
|
||||
codegen_fn_attrs.autodiff_item = ad;
|
||||
}
|
||||
|
||||
// When `no_builtins` is applied at the crate level, we should add the
|
||||
// `no-builtins` attribute to each function to ensure it takes effect in LTO.
|
||||
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
||||
|
@ -856,6 +869,109 @@ impl<'a> MixedExportNameAndNoMangleState<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)]
|
||||
/// macros. There are two forms. The pure one without args to mark primal functions (the functions
|
||||
/// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the
|
||||
/// placeholder functions. We wrote the rustc_autodiff attributes ourself, so this should never
|
||||
/// panic, unless we introduced a bug when parsing the autodiff macro.
|
||||
fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
|
||||
let attrs = tcx.get_attrs(id, sym::rustc_autodiff);
|
||||
|
||||
let attrs =
|
||||
attrs.filter(|attr| attr.name_or_empty() == sym::rustc_autodiff).collect::<Vec<_>>();
|
||||
|
||||
// check for exactly one autodiff attribute on placeholder functions.
|
||||
// There should only be one, since we generate a new placeholder per ad macro.
|
||||
// FIXME(ZuseZ4): re-enable this check. Currently we add multiple, which doesn't cause harm but
|
||||
// looks strange e.g. under cargo-expand.
|
||||
let attr = match &attrs[..] {
|
||||
[] => return None,
|
||||
[attr] => attr,
|
||||
// These two attributes are the same and unfortunately duplicated due to a previous bug.
|
||||
[attr, _attr2] => attr,
|
||||
_ => {
|
||||
//FIXME(ZuseZ4): Once we fixed our parser, we should also prohibit the two-attribute
|
||||
//branch above.
|
||||
span_bug!(attrs[1].span, "cg_ssa: rustc_autodiff should only exist once per source");
|
||||
}
|
||||
};
|
||||
|
||||
let list = attr.meta_item_list().unwrap_or_default();
|
||||
|
||||
// empty autodiff attribute macros (i.e. `#[autodiff]`) are used to mark source functions
|
||||
if list.is_empty() {
|
||||
return Some(AutoDiffAttrs::source());
|
||||
}
|
||||
|
||||
let [mode, input_activities @ .., ret_activity] = &list[..] else {
|
||||
span_bug!(attr.span, "rustc_autodiff attribute must contain mode and activities");
|
||||
};
|
||||
let mode = if let MetaItemInner::MetaItem(MetaItem { path: ref p1, .. }) = mode {
|
||||
p1.segments.first().unwrap().ident
|
||||
} else {
|
||||
span_bug!(attr.span, "rustc_autodiff attribute must contain mode");
|
||||
};
|
||||
|
||||
// parse mode
|
||||
let mode = match mode.as_str() {
|
||||
"Forward" => DiffMode::Forward,
|
||||
"Reverse" => DiffMode::Reverse,
|
||||
"ForwardFirst" => DiffMode::ForwardFirst,
|
||||
"ReverseFirst" => DiffMode::ReverseFirst,
|
||||
_ => {
|
||||
span_bug!(mode.span, "rustc_autodiff attribute contains invalid mode");
|
||||
}
|
||||
};
|
||||
|
||||
// First read the ret symbol from the attribute
|
||||
let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: ref p1, .. }) = ret_activity {
|
||||
p1.segments.first().unwrap().ident
|
||||
} else {
|
||||
span_bug!(attr.span, "rustc_autodiff attribute must contain the return activity");
|
||||
};
|
||||
|
||||
// Then parse it into an actual DiffActivity
|
||||
let Ok(ret_activity) = DiffActivity::from_str(ret_symbol.as_str()) else {
|
||||
span_bug!(ret_symbol.span, "invalid return activity");
|
||||
};
|
||||
|
||||
// Now parse all the intermediate (input) activities
|
||||
let mut arg_activities: Vec<DiffActivity> = vec![];
|
||||
for arg in input_activities {
|
||||
let arg_symbol = if let MetaItemInner::MetaItem(MetaItem { path: ref p2, .. }) = arg {
|
||||
match p2.segments.first() {
|
||||
Some(x) => x.ident,
|
||||
None => {
|
||||
span_bug!(
|
||||
arg.span(),
|
||||
"rustc_autodiff attribute must contain the input activity"
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
span_bug!(arg.span(), "rustc_autodiff attribute must contain the input activity");
|
||||
};
|
||||
|
||||
match DiffActivity::from_str(arg_symbol.as_str()) {
|
||||
Ok(arg_activity) => arg_activities.push(arg_activity),
|
||||
Err(_) => {
|
||||
span_bug!(arg_symbol.span, "invalid input activity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for &input in &arg_activities {
|
||||
if !valid_input_activity(mode, input) {
|
||||
span_bug!(attr.span, "Invalid input activity {} for {} mode", input, mode);
|
||||
}
|
||||
}
|
||||
if !valid_ret_activity(mode, ret_activity) {
|
||||
span_bug!(attr.span, "Invalid return activity {} for {} mode", ret_activity, mode);
|
||||
}
|
||||
|
||||
Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities })
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
|
||||
}
|
||||
|
|
|
@ -507,7 +507,7 @@ pub enum VTableNameKind {
|
|||
pub fn compute_debuginfo_vtable_name<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
t: Ty<'tcx>,
|
||||
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
|
||||
kind: VTableNameKind,
|
||||
) -> String {
|
||||
let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
|
||||
|
@ -530,8 +530,8 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
|
|||
}
|
||||
|
||||
if let Some(trait_ref) = trait_ref {
|
||||
let trait_ref = tcx
|
||||
.normalize_erasing_late_bound_regions(ty::TypingEnv::fully_monomorphized(), trait_ref);
|
||||
let trait_ref =
|
||||
tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref);
|
||||
push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
|
||||
visited.clear();
|
||||
push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
|
||||
|
|
|
@ -39,6 +39,10 @@ pub(crate) struct CguNotRecorded<'a> {
|
|||
pub cgu_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_autodiff_without_lto)]
|
||||
pub struct AutodiffWithoutLto;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_unknown_reuse_kind)]
|
||||
pub(crate) struct UnknownReuseKind {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{self, GenericArgKind, Ty};
|
||||
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt};
|
||||
use rustc_session::config::Lto;
|
||||
use rustc_symbol_mangling::typeid_for_trait_ref;
|
||||
use rustc_target::callconv::FnAbi;
|
||||
|
@ -72,12 +72,19 @@ impl<'a, 'tcx> VirtualIndex {
|
|||
|
||||
/// This takes a valid `self` receiver type and extracts the principal trait
|
||||
/// ref of the type. Return `None` if there is no principal trait.
|
||||
fn dyn_trait_in_self(ty: Ty<'_>) -> Option<ty::PolyExistentialTraitRef<'_>> {
|
||||
fn dyn_trait_in_self<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<ty::ExistentialTraitRef<'tcx>> {
|
||||
for arg in ty.peel_refs().walk() {
|
||||
if let GenericArgKind::Type(ty) = arg.unpack()
|
||||
&& let ty::Dynamic(data, _, _) = ty.kind()
|
||||
{
|
||||
return data.principal();
|
||||
// FIXME(arbitrary_self_types): This is likely broken for receivers which
|
||||
// have a "non-self" trait objects as a generic argument.
|
||||
return data
|
||||
.principal()
|
||||
.map(|principal| tcx.instantiate_bound_regions_with_erased(principal));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +103,7 @@ fn dyn_trait_in_self(ty: Ty<'_>) -> Option<ty::PolyExistentialTraitRef<'_>> {
|
|||
pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
|
||||
cx: &Cx,
|
||||
ty: Ty<'tcx>,
|
||||
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
|
||||
) -> Cx::Value {
|
||||
let tcx = cx.tcx();
|
||||
|
||||
|
@ -131,7 +138,7 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
|
||||
&& bx.cx().sess().lto() == Lto::Fat
|
||||
{
|
||||
if let Some(trait_ref) = dyn_trait_in_self(ty) {
|
||||
if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) {
|
||||
let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap();
|
||||
let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
|
||||
return func;
|
||||
|
|
|
@ -713,6 +713,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// and `#[track_caller]` adds an implicit third argument.
|
||||
(LangItem::PanicMisalignedPointerDereference, vec![required, found, location])
|
||||
}
|
||||
AssertKind::NullPointerDereference => {
|
||||
// It's `fn panic_null_pointer_dereference()`,
|
||||
// `#[track_caller]` adds an implicit argument.
|
||||
(LangItem::PanicNullPointerDereference, vec![location])
|
||||
}
|
||||
_ => {
|
||||
// It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument.
|
||||
(msg.panic_function(), vec![location])
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::ops::Range;
|
|||
|
||||
use rustc_abi::Size;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
|
||||
use rustc_middle::ty::{ExistentialTraitRef, Instance, Ty};
|
||||
use rustc_span::{SourceFile, Span, Symbol};
|
||||
use rustc_target::callconv::FnAbi;
|
||||
|
||||
|
@ -13,7 +13,7 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes {
|
|||
fn create_vtable_debuginfo(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
|
||||
trait_ref: Option<ExistentialTraitRef<'tcx>>,
|
||||
vtable: Self::Value,
|
||||
);
|
||||
|
||||
|
|
|
@ -10,11 +10,11 @@ use super::BackendTypes;
|
|||
pub trait MiscCodegenMethods<'tcx>: BackendTypes {
|
||||
fn vtables(
|
||||
&self,
|
||||
) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Self::Value>>;
|
||||
) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), Self::Value>>;
|
||||
fn apply_vcall_visibility_metadata(
|
||||
&self,
|
||||
_ty: Ty<'tcx>,
|
||||
_poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
_poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
|
||||
_vtable: Self::Value,
|
||||
) {
|
||||
}
|
||||
|
|
|
@ -634,7 +634,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place) => {
|
||||
// These are only inserted for slice length, so the place must already be indirect.
|
||||
// This implies we do not have to worry about whether the borrow escapes.
|
||||
assert!(place.is_indirect(), "fake borrows are always indirect");
|
||||
if !place.is_indirect() {
|
||||
self.tcx.dcx().span_delayed_bug(
|
||||
self.body.source_info(location).span,
|
||||
"fake borrows are always indirect",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::Cast(
|
||||
|
|
|
@ -508,6 +508,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||
found: eval_to_int(found)?,
|
||||
}
|
||||
}
|
||||
NullPointerDereference => NullPointerDereference,
|
||||
};
|
||||
Err(ConstEvalErrKind::AssertFailure(err)).into()
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::borrow::Cow;
|
|||
|
||||
use either::{Left, Right};
|
||||
use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
|
@ -693,25 +694,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
trace!("Virtual call dispatches to {fn_inst:#?}");
|
||||
// We can also do the lookup based on `def_id` and `dyn_ty`, and check that that
|
||||
// produces the same result.
|
||||
if cfg!(debug_assertions) {
|
||||
let tcx = *self.tcx;
|
||||
|
||||
let trait_def_id = tcx.trait_of_item(def_id).unwrap();
|
||||
let virtual_trait_ref =
|
||||
ty::TraitRef::from_method(tcx, trait_def_id, instance.args);
|
||||
let existential_trait_ref =
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
|
||||
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
|
||||
|
||||
let concrete_method = Instance::expect_resolve_for_vtable(
|
||||
tcx,
|
||||
self.typing_env,
|
||||
def_id,
|
||||
instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
|
||||
self.cur_span(),
|
||||
);
|
||||
assert_eq!(fn_inst, concrete_method);
|
||||
}
|
||||
self.assert_virtual_instance_matches_concrete(dyn_ty, def_id, instance, fn_inst);
|
||||
|
||||
// Adjust receiver argument. Layout can be any (thin) ptr.
|
||||
let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty);
|
||||
|
@ -744,6 +727,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_virtual_instance_matches_concrete(
|
||||
&self,
|
||||
dyn_ty: Ty<'tcx>,
|
||||
def_id: DefId,
|
||||
virtual_instance: ty::Instance<'tcx>,
|
||||
concrete_instance: ty::Instance<'tcx>,
|
||||
) {
|
||||
let tcx = *self.tcx;
|
||||
|
||||
let trait_def_id = tcx.trait_of_item(def_id).unwrap();
|
||||
let virtual_trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, virtual_instance.args);
|
||||
let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
|
||||
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
|
||||
|
||||
let concrete_method = Instance::expect_resolve_for_vtable(
|
||||
tcx,
|
||||
self.typing_env,
|
||||
def_id,
|
||||
virtual_instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
|
||||
self.cur_span(),
|
||||
);
|
||||
assert_eq!(concrete_instance, concrete_method);
|
||||
}
|
||||
|
||||
/// Initiate a tail call to this function -- popping the current stack frame, pushing the new
|
||||
/// stack frame and initializing the arguments.
|
||||
pub(super) fn init_fn_tail_call(
|
||||
|
|
|
@ -414,36 +414,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
|
||||
// Sanity-check that `supertrait_vtable_slot` in this type's vtable indeed produces
|
||||
// our destination trait.
|
||||
if cfg!(debug_assertions) {
|
||||
let vptr_entry_idx =
|
||||
self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty));
|
||||
let vtable_entries = self.vtable_entries(data_a.principal(), ty);
|
||||
if let Some(entry_idx) = vptr_entry_idx {
|
||||
let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) =
|
||||
vtable_entries.get(entry_idx)
|
||||
else {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"invalid vtable entry index in {} -> {} upcast",
|
||||
src_pointee_ty,
|
||||
dest_pointee_ty
|
||||
);
|
||||
};
|
||||
let erased_trait_ref = upcast_trait_ref
|
||||
.map_bound(|r| ty::ExistentialTraitRef::erase_self_ty(*self.tcx, r));
|
||||
assert!(
|
||||
data_b
|
||||
.principal()
|
||||
.is_some_and(|b| self.eq_in_param_env(erased_trait_ref, b))
|
||||
let vptr_entry_idx =
|
||||
self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty));
|
||||
let vtable_entries = self.vtable_entries(data_a.principal(), ty);
|
||||
if let Some(entry_idx) = vptr_entry_idx {
|
||||
let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) =
|
||||
vtable_entries.get(entry_idx)
|
||||
else {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"invalid vtable entry index in {} -> {} upcast",
|
||||
src_pointee_ty,
|
||||
dest_pointee_ty
|
||||
);
|
||||
} else {
|
||||
// In this case codegen would keep using the old vtable. We don't want to do
|
||||
// that as it has the wrong trait. The reason codegen can do this is that
|
||||
// one vtable is a prefix of the other, so we double-check that.
|
||||
let vtable_entries_b = self.vtable_entries(data_b.principal(), ty);
|
||||
assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b);
|
||||
};
|
||||
}
|
||||
let erased_trait_ref =
|
||||
ty::ExistentialTraitRef::erase_self_ty(*self.tcx, upcast_trait_ref);
|
||||
assert!(data_b.principal().is_some_and(|b| self.eq_in_param_env(
|
||||
erased_trait_ref,
|
||||
self.tcx.instantiate_bound_regions_with_erased(b)
|
||||
)));
|
||||
} else {
|
||||
// In this case codegen would keep using the old vtable. We don't want to do
|
||||
// that as it has the wrong trait. The reason codegen can do this is that
|
||||
// one vtable is a prefix of the other, so we double-check that.
|
||||
let vtable_entries_b = self.vtable_entries(data_b.principal(), ty);
|
||||
assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b);
|
||||
};
|
||||
|
||||
// Get the destination trait vtable and return that.
|
||||
let new_vptr = self.get_vtable_ptr(ty, data_b)?;
|
||||
|
|
|
@ -54,7 +54,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
) -> &'tcx [VtblEntry<'tcx>] {
|
||||
if let Some(trait_) = trait_ {
|
||||
let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty);
|
||||
let trait_ref = self.tcx.erase_regions(trait_ref);
|
||||
let trait_ref =
|
||||
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
|
||||
self.tcx.vtable_entries(trait_ref)
|
||||
} else {
|
||||
TyCtxt::COMMON_VTABLE_ENTRIES
|
||||
|
|
|
@ -76,6 +76,7 @@ pub mod sync;
|
|||
pub mod tagged_ptr;
|
||||
pub mod temp_dir;
|
||||
pub mod thinvec;
|
||||
pub mod thousands;
|
||||
pub mod transitive_relation;
|
||||
pub mod unhash;
|
||||
pub mod unord;
|
||||
|
|
16
compiler/rustc_data_structures/src/thousands/mod.rs
Normal file
16
compiler/rustc_data_structures/src/thousands/mod.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
//! This is an extremely bare-bones alternative to the `thousands` crate on
|
||||
//! crates.io, for printing large numbers in a readable fashion.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// Converts the number to a string, with underscores as the thousands separator.
|
||||
pub fn format_with_underscores(n: usize) -> String {
|
||||
let mut s = n.to_string();
|
||||
let mut i = s.len();
|
||||
while i > 3 {
|
||||
i -= 3;
|
||||
s.insert(i, '_');
|
||||
}
|
||||
s
|
||||
}
|
14
compiler/rustc_data_structures/src/thousands/tests.rs
Normal file
14
compiler/rustc_data_structures/src/thousands/tests.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_format_with_underscores() {
|
||||
assert_eq!("0", format_with_underscores(0));
|
||||
assert_eq!("1", format_with_underscores(1));
|
||||
assert_eq!("99", format_with_underscores(99));
|
||||
assert_eq!("345", format_with_underscores(345));
|
||||
assert_eq!("1_000", format_with_underscores(1_000));
|
||||
assert_eq!("12_001", format_with_underscores(12_001));
|
||||
assert_eq!("999_999", format_with_underscores(999_999));
|
||||
assert_eq!("1_000_000", format_with_underscores(1_000_000));
|
||||
assert_eq!("12_345_678", format_with_underscores(12_345_678));
|
||||
}
|
|
@ -7,6 +7,7 @@ use rustc_ast_pretty::pprust as pprust_ast;
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_mir_build::thir::print::{thir_flat, thir_tree};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode};
|
||||
use rustc_smir::rustc_internal::pretty::write_smir_pretty;
|
||||
|
@ -313,7 +314,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
|
|||
tcx.dcx().abort_if_errors();
|
||||
debug!("pretty printing THIR tree");
|
||||
for did in tcx.hir().body_owners() {
|
||||
let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did));
|
||||
let _ = writeln!(out, "{:?}:\n{}\n", did, thir_tree(tcx, did));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
@ -324,7 +325,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
|
|||
tcx.dcx().abort_if_errors();
|
||||
debug!("pretty printing THIR flat");
|
||||
for did in tcx.hir().body_owners() {
|
||||
let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did));
|
||||
let _ = writeln!(out, "{:?}:\n{}\n", did, thir_flat(tcx, did));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
|
|
@ -1136,7 +1136,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_dump_vtable, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/),
|
||||
|
|
|
@ -316,6 +316,7 @@ language_item_table! {
|
|||
PanicAsyncFnResumedPanic, sym::panic_const_async_fn_resumed_panic, panic_const_async_fn_resumed_panic, Target::Fn, GenericRequirement::None;
|
||||
PanicAsyncGenFnResumedPanic, sym::panic_const_async_gen_fn_resumed_panic, panic_const_async_gen_fn_resumed_panic, Target::Fn, GenericRequirement::None;
|
||||
PanicGenFnNonePanic, sym::panic_const_gen_fn_none_panic, panic_const_gen_fn_none_panic, Target::Fn, GenericRequirement::None;
|
||||
PanicNullPointerDereference, sym::panic_null_pointer_dereference, panic_null_pointer_dereference, Target::Fn, GenericRequirement::None;
|
||||
/// libstd panic entry point. Necessary for const eval to be able to catch it
|
||||
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
|
||||
|
||||
|
|
|
@ -424,12 +424,12 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
struct RemapLateParam<'a, 'tcx> {
|
||||
struct RemapLateParam<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mapping: &'a FxIndexMap<ty::LateParamRegionKind, ty::LateParamRegionKind>,
|
||||
mapping: FxIndexMap<ty::LateParamRegionKind, ty::LateParamRegionKind>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateParam<'_, 'tcx> {
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateParam<'tcx> {
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
@ -653,6 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
}))),
|
||||
terr,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
return Err(diag.emit());
|
||||
}
|
||||
|
@ -1070,6 +1071,7 @@ fn report_trait_method_mismatch<'tcx>(
|
|||
}))),
|
||||
terr,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
|
||||
diag.emit()
|
||||
|
@ -1862,6 +1864,7 @@ fn compare_const_predicate_entailment<'tcx>(
|
|||
}))),
|
||||
terr,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
return Err(diag.emit());
|
||||
};
|
||||
|
|
|
@ -299,8 +299,7 @@ fn report_mismatched_rpitit_signature<'tcx>(
|
|||
})
|
||||
.collect();
|
||||
|
||||
let mut return_ty =
|
||||
trait_m_sig.output().fold_with(&mut super::RemapLateParam { tcx, mapping: &mapping });
|
||||
let mut return_ty = trait_m_sig.output().fold_with(&mut super::RemapLateParam { tcx, mapping });
|
||||
|
||||
if tcx.asyncness(impl_m_def_id).is_async() && tcx.asyncness(trait_m_def_id).is_async() {
|
||||
let ty::Alias(ty::Projection, future_ty) = return_ty.kind() else {
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
// FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
|
||||
//
|
||||
// We don't do any drop checking during hir typeck.
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
|
||||
|
@ -32,7 +28,10 @@ use crate::hir::def_id::{DefId, LocalDefId};
|
|||
/// struct/enum definition for the nominal type itself (i.e.
|
||||
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
|
||||
///
|
||||
pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorGuaranteed> {
|
||||
pub(crate) fn check_drop_impl(
|
||||
tcx: TyCtxt<'_>,
|
||||
drop_impl_did: DefId,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
match tcx.impl_polarity(drop_impl_did) {
|
||||
ty::ImplPolarity::Positive => {}
|
||||
ty::ImplPolarity::Negative => {
|
||||
|
|
|
@ -199,7 +199,8 @@ pub fn check_intrinsic_type(
|
|||
let split: Vec<&str> = name_str.split('_').collect();
|
||||
assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
|
||||
|
||||
//We only care about the operation here
|
||||
// Each atomic op has variants with different suffixes (`_seq_cst`, `_acquire`, etc.). Use
|
||||
// string ops to strip the suffixes, because the variants all get the same treatment here.
|
||||
let (n_tps, inputs, output) = match split[1] {
|
||||
"cxchg" | "cxchgweak" => (
|
||||
1,
|
||||
|
|
|
@ -455,18 +455,14 @@ fn fn_sig_suggestion<'tcx>(
|
|||
let mut output = sig.output();
|
||||
|
||||
let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
|
||||
output = if let ty::Alias(_, alias_ty) = *output.kind() {
|
||||
tcx.explicit_item_self_bounds(alias_ty.def_id)
|
||||
output = if let ty::Alias(_, alias_ty) = *output.kind()
|
||||
&& let Some(output) = tcx
|
||||
.explicit_item_self_bounds(alias_ty.def_id)
|
||||
.iter_instantiated_copied(tcx, alias_ty.args)
|
||||
.find_map(|(bound, _)| {
|
||||
bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(
|
||||
ident.span,
|
||||
"expected async fn to have `impl Future` output, but it returns {output}"
|
||||
)
|
||||
})
|
||||
}) {
|
||||
output
|
||||
} else {
|
||||
span_bug!(
|
||||
ident.span,
|
||||
|
@ -649,6 +645,7 @@ pub fn check_function_signature<'tcx>(
|
|||
}))),
|
||||
err,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
return Err(diag.emit());
|
||||
}
|
||||
|
|
|
@ -2267,14 +2267,12 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
|
||||
fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> {
|
||||
let items = tcx.hir_module_items(module);
|
||||
let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id));
|
||||
res =
|
||||
res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
|
||||
res =
|
||||
res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
|
||||
res = res
|
||||
.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
|
||||
res = res.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item)));
|
||||
let res = items
|
||||
.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))
|
||||
.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)))
|
||||
.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)))
|
||||
.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)))
|
||||
.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item)));
|
||||
if module == LocalModDefId::CRATE_DEF_ID {
|
||||
super::entry::check_for_entry_fn(tcx);
|
||||
}
|
||||
|
|
|
@ -404,17 +404,12 @@ pub(crate) fn coerce_unsized_info<'tcx>(
|
|||
check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
|
||||
}
|
||||
|
||||
(&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => check_mutbl(
|
||||
ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a },
|
||||
ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b },
|
||||
&|ty| Ty::new_imm_ptr(tcx, ty),
|
||||
),
|
||||
|
||||
(&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => check_mutbl(
|
||||
ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a },
|
||||
ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b },
|
||||
&|ty| Ty::new_imm_ptr(tcx, ty),
|
||||
),
|
||||
(&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))
|
||||
| (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {
|
||||
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
|
||||
let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
|
||||
check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
|
||||
}
|
||||
|
||||
(&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
|
||||
if def_a.is_struct() && def_b.is_struct() =>
|
||||
|
|
|
@ -158,12 +158,12 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
|
|||
let trait_ref = trait_header.trait_ref.instantiate_identity();
|
||||
let trait_def = tcx.trait_def(trait_ref.def_id);
|
||||
|
||||
res = res.and(check_impl(tcx, impl_def_id, trait_ref, trait_def));
|
||||
res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref));
|
||||
|
||||
res = res.and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def));
|
||||
res = res.and(tcx.ensure().orphan_check_impl(impl_def_id));
|
||||
res = res.and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header));
|
||||
res = res
|
||||
.and(check_impl(tcx, impl_def_id, trait_ref, trait_def))
|
||||
.and(check_object_overlap(tcx, impl_def_id, trait_ref))
|
||||
.and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def))
|
||||
.and(tcx.ensure().orphan_check_impl(impl_def_id))
|
||||
.and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header));
|
||||
}
|
||||
|
||||
res
|
||||
|
@ -199,10 +199,9 @@ fn check_object_overlap<'tcx>(
|
|||
|
||||
for component_def_id in component_def_ids {
|
||||
if !tcx.is_dyn_compatible(component_def_id) {
|
||||
// FIXME(dyn_compat_renaming): Rename test and update comment.
|
||||
// Without the 'dyn_compatible_for_dispatch' feature this is an error
|
||||
// which will be reported by wfcheck. Ignore it here.
|
||||
// This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
|
||||
// This is tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`.
|
||||
// With the feature enabled, the trait is not implemented automatically,
|
||||
// so this is valid.
|
||||
} else {
|
||||
|
|
|
@ -57,7 +57,7 @@ mod type_of;
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
resolve_bound_vars::provide(providers);
|
||||
*providers = Providers {
|
||||
type_of: type_of::type_of,
|
||||
|
@ -122,7 +122,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
/// `ItemCtxt` is parameterized by a `DefId` that it uses to satisfy
|
||||
/// `probe_ty_param_bounds` requests, drawing the information from
|
||||
/// the HIR (`hir::Generics`), recursively.
|
||||
pub struct ItemCtxt<'tcx> {
|
||||
pub(crate) struct ItemCtxt<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item_def_id: LocalDefId,
|
||||
tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
|
||||
|
@ -148,7 +148,7 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct CollectItemTypesVisitor<'tcx> {
|
||||
pub(crate) struct CollectItemTypesVisitor<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
|
@ -364,19 +364,19 @@ fn bad_placeholder<'cx, 'tcx>(
|
|||
}
|
||||
|
||||
impl<'tcx> ItemCtxt<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> {
|
||||
pub(crate) fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> {
|
||||
ItemCtxt { tcx, item_def_id, tainted_by_errors: Cell::new(None) }
|
||||
}
|
||||
|
||||
pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
pub(crate) fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
self.lowerer().lower_ty(hir_ty)
|
||||
}
|
||||
|
||||
pub fn hir_id(&self) -> hir::HirId {
|
||||
pub(crate) fn hir_id(&self) -> hir::HirId {
|
||||
self.tcx.local_def_id_to_hir_id(self.item_def_id)
|
||||
}
|
||||
|
||||
pub fn node(&self) -> hir::Node<'tcx> {
|
||||
pub(crate) fn node(&self) -> hir::Node<'tcx> {
|
||||
self.tcx.hir_node(self.hir_id())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::sym;
|
||||
|
||||
pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
|
||||
|
@ -87,3 +88,82 @@ pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||
for id in tcx.hir().items() {
|
||||
let def_id = id.owner_id.def_id;
|
||||
|
||||
let Some(attr) = tcx.get_attr(def_id, sym::rustc_dump_vtable) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let vtable_entries = match tcx.hir().item(id).kind {
|
||||
hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
|
||||
let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity();
|
||||
if trait_ref.has_non_region_param() {
|
||||
tcx.dcx().span_err(
|
||||
attr.span,
|
||||
"`rustc_dump_vtable` must be applied to non-generic impl",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if !tcx.is_dyn_compatible(trait_ref.def_id) {
|
||||
tcx.dcx().span_err(
|
||||
attr.span,
|
||||
"`rustc_dump_vtable` must be applied to dyn-compatible trait",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let Ok(trait_ref) = tcx
|
||||
.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref)
|
||||
else {
|
||||
tcx.dcx().span_err(
|
||||
attr.span,
|
||||
"`rustc_dump_vtable` applied to impl header that cannot be normalized",
|
||||
);
|
||||
continue;
|
||||
};
|
||||
tcx.vtable_entries(trait_ref)
|
||||
}
|
||||
hir::ItemKind::TyAlias(_, _) => {
|
||||
let ty = tcx.type_of(def_id).instantiate_identity();
|
||||
if ty.has_non_region_param() {
|
||||
tcx.dcx().span_err(
|
||||
attr.span,
|
||||
"`rustc_dump_vtable` must be applied to non-generic type",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let Ok(ty) =
|
||||
tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
|
||||
else {
|
||||
tcx.dcx().span_err(
|
||||
attr.span,
|
||||
"`rustc_dump_vtable` applied to type alias that cannot be normalized",
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let ty::Dynamic(data, _, _) = *ty.kind() else {
|
||||
tcx.dcx().span_err(attr.span, "`rustc_dump_vtable` to type alias of dyn type");
|
||||
continue;
|
||||
};
|
||||
if let Some(principal) = data.principal() {
|
||||
tcx.vtable_entries(
|
||||
tcx.instantiate_bound_regions_with_erased(principal).with_self_ty(tcx, ty),
|
||||
)
|
||||
} else {
|
||||
TyCtxt::COMMON_VTABLE_ENTRIES
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx().span_err(
|
||||
attr.span,
|
||||
"`rustc_dump_vtable` only applies to impl, or type alias of dyn type",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
tcx.dcx().span_err(tcx.def_span(def_id), format!("vtable entries: {vtable_entries:#?}"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,13 +12,11 @@ use std::ops::ControlFlow;
|
|||
|
||||
use rustc_ast::visit::walk_list;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
|
||||
use rustc_hir::{
|
||||
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap,
|
||||
LifetimeName, Node,
|
||||
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeName, Node,
|
||||
};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
|
@ -26,7 +24,7 @@ use rustc_middle::middle::resolve_bound_vars::*;
|
|||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::def_id::{DefId, LocalDefId, LocalDefIdMap};
|
||||
use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use tracing::{debug, debug_span, instrument};
|
||||
|
||||
|
@ -62,33 +60,9 @@ impl ResolvedArg {
|
|||
}
|
||||
}
|
||||
|
||||
/// Maps the id of each bound variable reference to the variable decl
|
||||
/// that it corresponds to.
|
||||
///
|
||||
/// FIXME. This struct gets converted to a `ResolveBoundVars` for
|
||||
/// actual use. It has the same data, but indexed by `LocalDefId`. This
|
||||
/// is silly.
|
||||
#[derive(Debug, Default)]
|
||||
struct NamedVarMap {
|
||||
// maps from every use of a named (not anonymous) bound var to a
|
||||
// `ResolvedArg` describing how that variable is bound
|
||||
defs: ItemLocalMap<ResolvedArg>,
|
||||
|
||||
// Maps relevant hir items to the bound vars on them. These include:
|
||||
// - function defs
|
||||
// - function pointers
|
||||
// - closures
|
||||
// - trait refs
|
||||
// - bound types (like `T` in `for<'a> T<'a>: Foo`)
|
||||
late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>,
|
||||
|
||||
// List captured variables for each opaque type.
|
||||
opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>,
|
||||
}
|
||||
|
||||
struct BoundVarContext<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
map: &'a mut NamedVarMap,
|
||||
rbv: &'a mut ResolveBoundVars,
|
||||
scope: ScopeRef<'a>,
|
||||
}
|
||||
|
||||
|
@ -267,19 +241,12 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
|
||||
/// Computes the `ResolveBoundVars` map that contains data for an entire `Item`.
|
||||
/// You should not read the result of this query directly, but rather use
|
||||
/// `named_variable_map`, `is_late_bound_map`, etc.
|
||||
/// `named_variable_map`, `late_bound_vars_map`, etc.
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars {
|
||||
let mut named_variable_map = NamedVarMap {
|
||||
defs: Default::default(),
|
||||
late_bound_vars: Default::default(),
|
||||
opaque_captured_lifetimes: Default::default(),
|
||||
};
|
||||
let mut visitor = BoundVarContext {
|
||||
tcx,
|
||||
map: &mut named_variable_map,
|
||||
scope: &Scope::Root { opt_parent_item: None },
|
||||
};
|
||||
let mut rbv = ResolveBoundVars::default();
|
||||
let mut visitor =
|
||||
BoundVarContext { tcx, rbv: &mut rbv, scope: &Scope::Root { opt_parent_item: None } };
|
||||
match tcx.hir_owner_node(local_def_id) {
|
||||
hir::OwnerNode::Item(item) => visitor.visit_item(item),
|
||||
hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
|
||||
|
@ -299,19 +266,10 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
|
|||
hir::OwnerNode::Synthetic => unreachable!(),
|
||||
}
|
||||
|
||||
let defs = named_variable_map.defs.into_sorted_stable_ord();
|
||||
let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord();
|
||||
let opaque_captured_lifetimes = named_variable_map.opaque_captured_lifetimes;
|
||||
let rl = ResolveBoundVars {
|
||||
defs: SortedMap::from_presorted_elements(defs),
|
||||
late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars),
|
||||
opaque_captured_lifetimes,
|
||||
};
|
||||
|
||||
debug!(?rl.defs);
|
||||
debug!(?rl.late_bound_vars);
|
||||
debug!(?rl.opaque_captured_lifetimes);
|
||||
rl
|
||||
debug!(?rbv.defs);
|
||||
debug!(?rbv.late_bound_vars);
|
||||
debug!(?rbv.opaque_captured_lifetimes);
|
||||
rbv
|
||||
}
|
||||
|
||||
fn late_arg_as_bound_arg<'tcx>(
|
||||
|
@ -404,7 +362,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
Scope::Binder { hir_id, .. } => {
|
||||
// Nested poly trait refs have the binders concatenated
|
||||
let mut full_binders =
|
||||
self.map.late_bound_vars.entry(hir_id.local_id).or_default().clone();
|
||||
self.rbv.late_bound_vars.get_mut_or_insert_default(hir_id.local_id).clone();
|
||||
full_binders.extend(supertrait_bound_vars);
|
||||
break (full_binders, BinderScopeType::Concatenating);
|
||||
}
|
||||
|
@ -646,7 +604,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
|
||||
let captures = captures.into_inner().into_iter().collect();
|
||||
debug!(?captures);
|
||||
self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures);
|
||||
self.rbv.opaque_captured_lifetimes.insert(opaque.def_id, captures);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
@ -848,7 +806,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
hir::TyKind::Ref(lifetime_ref, ref mt) => {
|
||||
self.visit_lifetime(lifetime_ref);
|
||||
let scope = Scope::ObjectLifetimeDefault {
|
||||
lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
|
||||
lifetime: self.rbv.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
|
||||
s: self.scope,
|
||||
};
|
||||
self.with(scope, |this| this.visit_ty_unambig(mt.ty));
|
||||
|
@ -966,7 +924,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
let bound_vars: Vec<_> =
|
||||
self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect();
|
||||
let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
|
||||
self.map.late_bound_vars.insert(hir_id.local_id, bound_vars);
|
||||
self.rbv.late_bound_vars.insert(hir_id.local_id, bound_vars);
|
||||
}
|
||||
self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
|
||||
intravisit::walk_fn_kind(self, fk);
|
||||
|
@ -1140,8 +1098,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
where
|
||||
F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>),
|
||||
{
|
||||
let BoundVarContext { tcx, map, .. } = self;
|
||||
let mut this = BoundVarContext { tcx: *tcx, map, scope: &wrap_scope };
|
||||
let BoundVarContext { tcx, rbv, .. } = self;
|
||||
let mut this = BoundVarContext { tcx: *tcx, rbv, scope: &wrap_scope };
|
||||
let span = debug_span!("scope", scope = ?this.scope.debug_truncated());
|
||||
{
|
||||
let _enter = span.enter();
|
||||
|
@ -1150,10 +1108,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec<ty::BoundVariableKind>) {
|
||||
if let Some(old) = self.map.late_bound_vars.insert(hir_id.local_id, binder) {
|
||||
if let Some(old) = self.rbv.late_bound_vars.insert(hir_id.local_id, binder) {
|
||||
bug!(
|
||||
"overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
|
||||
self.map.late_bound_vars[&hir_id.local_id]
|
||||
self.rbv.late_bound_vars[&hir_id.local_id]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1597,9 +1555,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
kind.descr(param_def_id.to_def_id())
|
||||
),
|
||||
};
|
||||
self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
|
||||
self.rbv.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
|
||||
} else {
|
||||
self.map.defs.insert(hir_id.local_id, def);
|
||||
self.rbv.defs.insert(hir_id.local_id, def);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1632,7 +1590,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id()))
|
||||
}
|
||||
});
|
||||
self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
|
||||
self.rbv.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
|
||||
return;
|
||||
}
|
||||
Scope::Root { .. } => break,
|
||||
|
@ -1725,7 +1683,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let map = &self.map;
|
||||
let rbv = &self.rbv;
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
|
||||
// `type_def_id` points to an item, so there is nothing to inherit generics from.
|
||||
|
@ -1744,7 +1702,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
// This index can be used with `generic_args` since `parent_count == 0`.
|
||||
let index = generics.param_def_id_to_index[¶m_def_id] as usize;
|
||||
generic_args.args.get(index).and_then(|arg| match arg {
|
||||
GenericArg::Lifetime(lt) => map.defs.get(<.hir_id.local_id).copied(),
|
||||
GenericArg::Lifetime(lt) => rbv.defs.get(<.hir_id.local_id).copied(),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
@ -2042,7 +2000,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
#[instrument(level = "debug", skip(self))]
|
||||
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) {
|
||||
debug!(span = ?lifetime_ref.ident.span);
|
||||
self.map.defs.insert(lifetime_ref.hir_id.local_id, def);
|
||||
self.rbv.defs.insert(lifetime_ref.hir_id.local_id, def);
|
||||
}
|
||||
|
||||
// When we have a return type notation type in a where clause, like
|
||||
|
@ -2197,7 +2155,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
// See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`.
|
||||
// And this is exercised in:
|
||||
// `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`.
|
||||
let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id.local_id).unwrap();
|
||||
let existing_bound_vars = self.rbv.late_bound_vars.get_mut(&hir_id.local_id).unwrap();
|
||||
let existing_bound_vars_saved = existing_bound_vars.clone();
|
||||
existing_bound_vars.extend(bound_vars);
|
||||
self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);
|
||||
|
|
|
@ -100,213 +100,156 @@ enum InheritanceKind {
|
|||
Own,
|
||||
}
|
||||
|
||||
struct GenericsBuilder<'tcx> {
|
||||
fn build_generics<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
sig_id: DefId,
|
||||
parent: Option<DefId>,
|
||||
inh_kind: InheritanceKind,
|
||||
}
|
||||
) -> ty::Generics {
|
||||
let mut own_params = vec![];
|
||||
|
||||
impl<'tcx> GenericsBuilder<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>, sig_id: DefId) -> GenericsBuilder<'tcx> {
|
||||
GenericsBuilder { tcx, sig_id, parent: None, inh_kind: InheritanceKind::WithParent(false) }
|
||||
let sig_generics = tcx.generics_of(sig_id);
|
||||
if let InheritanceKind::WithParent(has_self) = inh_kind
|
||||
&& let Some(parent_def_id) = sig_generics.parent
|
||||
{
|
||||
let sig_parent_generics = tcx.generics_of(parent_def_id);
|
||||
own_params.append(&mut sig_parent_generics.own_params.clone());
|
||||
if !has_self {
|
||||
own_params.remove(0);
|
||||
}
|
||||
}
|
||||
own_params.append(&mut sig_generics.own_params.clone());
|
||||
|
||||
fn with_parent(mut self, parent: DefId) -> Self {
|
||||
self.parent = Some(parent);
|
||||
self
|
||||
}
|
||||
// Lifetime parameters must be declared before type and const parameters.
|
||||
// Therefore, When delegating from a free function to a associated function,
|
||||
// generic parameters need to be reordered:
|
||||
//
|
||||
// trait Trait<'a, A> {
|
||||
// fn foo<'b, B>(...) {...}
|
||||
// }
|
||||
//
|
||||
// reuse Trait::foo;
|
||||
// desugaring:
|
||||
// fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
|
||||
// Trait::foo(...)
|
||||
// }
|
||||
own_params.sort_by_key(|key| key.kind.is_ty_or_const());
|
||||
|
||||
fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self {
|
||||
self.inh_kind = inh_kind;
|
||||
self
|
||||
}
|
||||
let param_def_id_to_index =
|
||||
own_params.iter().map(|param| (param.def_id, param.index)).collect();
|
||||
|
||||
fn build(self) -> ty::Generics {
|
||||
let mut own_params = vec![];
|
||||
let (parent_count, has_self) = if let Some(def_id) = parent {
|
||||
let parent_generics = tcx.generics_of(def_id);
|
||||
let parent_kind = tcx.def_kind(def_id);
|
||||
(parent_generics.count(), parent_kind == DefKind::Trait)
|
||||
} else {
|
||||
(0, false)
|
||||
};
|
||||
|
||||
let sig_generics = self.tcx.generics_of(self.sig_id);
|
||||
if let InheritanceKind::WithParent(has_self) = self.inh_kind
|
||||
&& let Some(parent_def_id) = sig_generics.parent
|
||||
for (idx, param) in own_params.iter_mut().enumerate() {
|
||||
param.index = (idx + parent_count) as u32;
|
||||
// FIXME(fn_delegation): Default parameters are not inherited, because they are
|
||||
// not permitted in functions. Therefore, there are 2 options here:
|
||||
//
|
||||
// - We can create non-default generic parameters.
|
||||
// - We can substitute default parameters into the signature.
|
||||
//
|
||||
// At the moment, first option has been selected as the most general.
|
||||
if let ty::GenericParamDefKind::Type { has_default, .. }
|
||||
| ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind
|
||||
{
|
||||
let sig_parent_generics = self.tcx.generics_of(parent_def_id);
|
||||
own_params.append(&mut sig_parent_generics.own_params.clone());
|
||||
if !has_self {
|
||||
own_params.remove(0);
|
||||
}
|
||||
*has_default = false;
|
||||
}
|
||||
own_params.append(&mut sig_generics.own_params.clone());
|
||||
}
|
||||
|
||||
// Lifetime parameters must be declared before type and const parameters.
|
||||
// Therefore, When delegating from a free function to a associated function,
|
||||
// generic parameters need to be reordered:
|
||||
//
|
||||
// trait Trait<'a, A> {
|
||||
// fn foo<'b, B>(...) {...}
|
||||
// }
|
||||
//
|
||||
// reuse Trait::foo;
|
||||
// desugaring:
|
||||
// fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
|
||||
// Trait::foo(...)
|
||||
// }
|
||||
own_params.sort_by_key(|key| key.kind.is_ty_or_const());
|
||||
|
||||
let param_def_id_to_index =
|
||||
own_params.iter().map(|param| (param.def_id, param.index)).collect();
|
||||
|
||||
let (parent_count, has_self) = if let Some(def_id) = self.parent {
|
||||
let parent_generics = self.tcx.generics_of(def_id);
|
||||
let parent_kind = self.tcx.def_kind(def_id);
|
||||
(parent_generics.count(), parent_kind == DefKind::Trait)
|
||||
} else {
|
||||
(0, false)
|
||||
};
|
||||
|
||||
for (idx, param) in own_params.iter_mut().enumerate() {
|
||||
param.index = (idx + parent_count) as u32;
|
||||
// FIXME(fn_delegation): Default parameters are not inherited, because they are
|
||||
// not permitted in functions. Therefore, there are 2 options here:
|
||||
//
|
||||
// - We can create non-default generic parameters.
|
||||
// - We can substitute default parameters into the signature.
|
||||
//
|
||||
// At the moment, first option has been selected as the most general.
|
||||
if let ty::GenericParamDefKind::Type { has_default, .. }
|
||||
| ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind
|
||||
{
|
||||
*has_default = false;
|
||||
}
|
||||
}
|
||||
|
||||
ty::Generics {
|
||||
parent: self.parent,
|
||||
parent_count,
|
||||
own_params,
|
||||
param_def_id_to_index,
|
||||
has_self,
|
||||
has_late_bound_regions: sig_generics.has_late_bound_regions,
|
||||
}
|
||||
ty::Generics {
|
||||
parent,
|
||||
parent_count,
|
||||
own_params,
|
||||
param_def_id_to_index,
|
||||
has_self,
|
||||
has_late_bound_regions: sig_generics.has_late_bound_regions,
|
||||
}
|
||||
}
|
||||
|
||||
struct PredicatesBuilder<'tcx> {
|
||||
fn build_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
sig_id: DefId,
|
||||
parent: Option<DefId>,
|
||||
inh_kind: InheritanceKind,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> PredicatesBuilder<'tcx> {
|
||||
fn new(
|
||||
) -> ty::GenericPredicates<'tcx> {
|
||||
struct PredicatesCollector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
preds: Vec<(ty::Clause<'tcx>, Span)>,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
sig_id: DefId,
|
||||
) -> PredicatesBuilder<'tcx> {
|
||||
PredicatesBuilder {
|
||||
tcx,
|
||||
sig_id,
|
||||
parent: None,
|
||||
inh_kind: InheritanceKind::WithParent(false),
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
||||
fn with_parent(mut self, parent: DefId) -> Self {
|
||||
self.parent = Some(parent);
|
||||
self
|
||||
}
|
||||
|
||||
fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self {
|
||||
self.inh_kind = inh_kind;
|
||||
self
|
||||
}
|
||||
|
||||
fn build(self) -> ty::GenericPredicates<'tcx> {
|
||||
struct PredicatesCollector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
preds: Vec<(ty::Clause<'tcx>, Span)>,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
impl<'tcx> PredicatesCollector<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> {
|
||||
PredicatesCollector { tcx, preds: vec![], args }
|
||||
}
|
||||
|
||||
impl<'tcx> PredicatesCollector<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> {
|
||||
PredicatesCollector { tcx, preds: vec![], args }
|
||||
}
|
||||
|
||||
fn with_own_preds(
|
||||
mut self,
|
||||
f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> Self {
|
||||
let preds = f(def_id).instantiate_own(self.tcx, self.args);
|
||||
self.preds.extend(preds);
|
||||
self
|
||||
}
|
||||
|
||||
fn with_preds(
|
||||
mut self,
|
||||
f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy,
|
||||
def_id: DefId,
|
||||
) -> Self {
|
||||
let preds = f(def_id);
|
||||
if let Some(parent_def_id) = preds.parent {
|
||||
self = self.with_own_preds(f, parent_def_id);
|
||||
}
|
||||
self.with_own_preds(f, def_id)
|
||||
}
|
||||
fn with_own_preds(
|
||||
mut self,
|
||||
f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> Self {
|
||||
let preds = f(def_id).instantiate_own(self.tcx, self.args);
|
||||
self.preds.extend(preds);
|
||||
self
|
||||
}
|
||||
let collector = PredicatesCollector::new(self.tcx, self.args);
|
||||
|
||||
// `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate.
|
||||
// Note: `predicates_of` query can also add inferred outlives predicates, but that
|
||||
// is not the case here as `sig_id` is either a trait or a function.
|
||||
let preds = match self.inh_kind {
|
||||
InheritanceKind::WithParent(false) => {
|
||||
collector.with_preds(|def_id| self.tcx.explicit_predicates_of(def_id), self.sig_id)
|
||||
fn with_preds(
|
||||
mut self,
|
||||
f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy,
|
||||
def_id: DefId,
|
||||
) -> Self {
|
||||
let preds = f(def_id);
|
||||
if let Some(parent_def_id) = preds.parent {
|
||||
self = self.with_own_preds(f, parent_def_id);
|
||||
}
|
||||
InheritanceKind::WithParent(true) => {
|
||||
collector.with_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id)
|
||||
}
|
||||
InheritanceKind::Own => {
|
||||
collector.with_own_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id)
|
||||
}
|
||||
}
|
||||
.preds;
|
||||
|
||||
ty::GenericPredicates {
|
||||
parent: self.parent,
|
||||
predicates: self.tcx.arena.alloc_from_iter(preds),
|
||||
self.with_own_preds(f, def_id)
|
||||
}
|
||||
}
|
||||
let collector = PredicatesCollector::new(tcx, args);
|
||||
|
||||
// `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate.
|
||||
// Note: `predicates_of` query can also add inferred outlives predicates, but that
|
||||
// is not the case here as `sig_id` is either a trait or a function.
|
||||
let preds = match inh_kind {
|
||||
InheritanceKind::WithParent(false) => {
|
||||
collector.with_preds(|def_id| tcx.explicit_predicates_of(def_id), sig_id)
|
||||
}
|
||||
InheritanceKind::WithParent(true) => {
|
||||
collector.with_preds(|def_id| tcx.predicates_of(def_id), sig_id)
|
||||
}
|
||||
InheritanceKind::Own => {
|
||||
collector.with_own_preds(|def_id| tcx.predicates_of(def_id), sig_id)
|
||||
}
|
||||
}
|
||||
.preds;
|
||||
|
||||
ty::GenericPredicates { parent, predicates: tcx.arena.alloc_from_iter(preds) }
|
||||
}
|
||||
|
||||
struct GenericArgsBuilder<'tcx> {
|
||||
fn build_generic_args<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
remap_table: RemapTable,
|
||||
sig_id: DefId,
|
||||
def_id: LocalDefId,
|
||||
}
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> ty::GenericArgsRef<'tcx> {
|
||||
let caller_generics = tcx.generics_of(def_id);
|
||||
let callee_generics = tcx.generics_of(sig_id);
|
||||
|
||||
impl<'tcx> GenericArgsBuilder<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>, sig_id: DefId, def_id: LocalDefId) -> GenericArgsBuilder<'tcx> {
|
||||
GenericArgsBuilder { tcx, remap_table: FxHashMap::default(), sig_id, def_id }
|
||||
let mut remap_table = FxHashMap::default();
|
||||
for caller_param in &caller_generics.own_params {
|
||||
let callee_index = callee_generics.param_def_id_to_index(tcx, caller_param.def_id).unwrap();
|
||||
remap_table.insert(callee_index, caller_param.index);
|
||||
}
|
||||
|
||||
fn build_from_args(mut self, args: ty::GenericArgsRef<'tcx>) -> ty::GenericArgsRef<'tcx> {
|
||||
let caller_generics = self.tcx.generics_of(self.def_id);
|
||||
let callee_generics = self.tcx.generics_of(self.sig_id);
|
||||
|
||||
for caller_param in &caller_generics.own_params {
|
||||
let callee_index =
|
||||
callee_generics.param_def_id_to_index(self.tcx, caller_param.def_id).unwrap();
|
||||
self.remap_table.insert(callee_index, caller_param.index);
|
||||
}
|
||||
|
||||
let mut folder = ParamIndexRemapper { tcx: self.tcx, remap_table: self.remap_table };
|
||||
args.fold_with(&mut folder)
|
||||
}
|
||||
let mut folder = ParamIndexRemapper { tcx, remap_table };
|
||||
args.fold_with(&mut folder)
|
||||
}
|
||||
|
||||
fn create_generic_args<'tcx>(
|
||||
|
@ -314,8 +257,6 @@ fn create_generic_args<'tcx>(
|
|||
def_id: LocalDefId,
|
||||
sig_id: DefId,
|
||||
) -> ty::GenericArgsRef<'tcx> {
|
||||
let builder = GenericArgsBuilder::new(tcx, sig_id, def_id);
|
||||
|
||||
let caller_kind = fn_kind(tcx, def_id.into());
|
||||
let callee_kind = fn_kind(tcx, sig_id);
|
||||
match (caller_kind, callee_kind) {
|
||||
|
@ -325,7 +266,7 @@ fn create_generic_args<'tcx>(
|
|||
| (FnKind::AssocTrait, FnKind::Free)
|
||||
| (FnKind::AssocTrait, FnKind::AssocTrait) => {
|
||||
let args = ty::GenericArgs::identity_for_item(tcx, sig_id);
|
||||
builder.build_from_args(args)
|
||||
build_generic_args(tcx, sig_id, def_id, args)
|
||||
}
|
||||
|
||||
(FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
|
||||
|
@ -335,8 +276,9 @@ fn create_generic_args<'tcx>(
|
|||
tcx.impl_trait_header(parent).unwrap().trait_ref.instantiate_identity().args;
|
||||
|
||||
let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id);
|
||||
let method_args = tcx.mk_args_from_iter(trait_args.iter().skip(callee_generics.parent_count));
|
||||
let method_args = builder.build_from_args(method_args);
|
||||
let method_args =
|
||||
tcx.mk_args_from_iter(trait_args.iter().skip(callee_generics.parent_count));
|
||||
let method_args = build_generic_args(tcx, sig_id, def_id, method_args);
|
||||
|
||||
tcx.mk_args_from_iter(parent_args.iter().chain(method_args))
|
||||
}
|
||||
|
@ -347,16 +289,16 @@ fn create_generic_args<'tcx>(
|
|||
let generic_self_ty = ty::GenericArg::from(self_ty);
|
||||
|
||||
let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id);
|
||||
let trait_args = builder.build_from_args(trait_args);
|
||||
let trait_args = build_generic_args(tcx, sig_id, def_id, trait_args);
|
||||
|
||||
let args = std::iter::once(generic_self_ty).chain(trait_args.iter().skip(1));
|
||||
tcx.mk_args_from_iter(args)
|
||||
}
|
||||
|
||||
// For trait impl's `sig_id` is always equal to the corresponding trait method.
|
||||
// For inherent methods delegation is not yet supported.
|
||||
(FnKind::AssocTraitImpl, _)
|
||||
| (_, FnKind::AssocTraitImpl)
|
||||
// Delegation to inherent methods is not yet supported.
|
||||
| (_, FnKind::AssocInherentImpl) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -377,39 +319,31 @@ pub(crate) fn inherit_generics_for_delegation_item<'tcx>(
|
|||
def_id: LocalDefId,
|
||||
sig_id: DefId,
|
||||
) -> ty::Generics {
|
||||
let builder = GenericsBuilder::new(tcx, sig_id);
|
||||
|
||||
let caller_kind = fn_kind(tcx, def_id.into());
|
||||
let callee_kind = fn_kind(tcx, sig_id);
|
||||
match (caller_kind, callee_kind) {
|
||||
(FnKind::Free, FnKind::Free)
|
||||
| (FnKind::Free, FnKind::AssocTrait) => builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build(),
|
||||
(FnKind::Free, FnKind::Free) | (FnKind::Free, FnKind::AssocTrait) => {
|
||||
build_generics(tcx, sig_id, None, InheritanceKind::WithParent(true))
|
||||
}
|
||||
|
||||
(FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
|
||||
builder
|
||||
.with_parent(tcx.parent(def_id.into()))
|
||||
.with_inheritance_kind(InheritanceKind::Own)
|
||||
.build()
|
||||
build_generics(tcx, sig_id, Some(tcx.parent(def_id.into())), InheritanceKind::Own)
|
||||
}
|
||||
|
||||
(FnKind::AssocInherentImpl, FnKind::AssocTrait)
|
||||
| (FnKind::AssocTrait, FnKind::AssocTrait) => {
|
||||
builder
|
||||
.with_parent(tcx.parent(def_id.into()))
|
||||
.build()
|
||||
}
|
||||
|
||||
(FnKind::AssocInherentImpl, FnKind::Free)
|
||||
| (FnKind::AssocTrait, FnKind::Free) => {
|
||||
builder
|
||||
.with_parent(tcx.parent(def_id.into()))
|
||||
.build()
|
||||
}
|
||||
| (FnKind::AssocTrait, FnKind::AssocTrait)
|
||||
| (FnKind::AssocInherentImpl, FnKind::Free)
|
||||
| (FnKind::AssocTrait, FnKind::Free) => build_generics(
|
||||
tcx,
|
||||
sig_id,
|
||||
Some(tcx.parent(def_id.into())),
|
||||
InheritanceKind::WithParent(false),
|
||||
),
|
||||
|
||||
// For trait impl's `sig_id` is always equal to the corresponding trait method.
|
||||
// For inherent methods delegation is not yet supported.
|
||||
(FnKind::AssocTraitImpl, _)
|
||||
| (_, FnKind::AssocTraitImpl)
|
||||
// Delegation to inherent methods is not yet supported.
|
||||
| (_, FnKind::AssocInherentImpl) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -420,36 +354,36 @@ pub(crate) fn inherit_predicates_for_delegation_item<'tcx>(
|
|||
sig_id: DefId,
|
||||
) -> ty::GenericPredicates<'tcx> {
|
||||
let args = create_generic_args(tcx, def_id, sig_id);
|
||||
let builder = PredicatesBuilder::new(tcx, args, sig_id);
|
||||
|
||||
let caller_kind = fn_kind(tcx, def_id.into());
|
||||
let callee_kind = fn_kind(tcx, sig_id);
|
||||
match (caller_kind, callee_kind) {
|
||||
(FnKind::Free, FnKind::Free)
|
||||
| (FnKind::Free, FnKind::AssocTrait) => {
|
||||
builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build()
|
||||
(FnKind::Free, FnKind::Free) | (FnKind::Free, FnKind::AssocTrait) => {
|
||||
build_predicates(tcx, sig_id, None, InheritanceKind::WithParent(true), args)
|
||||
}
|
||||
|
||||
(FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
|
||||
builder
|
||||
.with_parent(tcx.parent(def_id.into()))
|
||||
.with_inheritance_kind(InheritanceKind::Own)
|
||||
.build()
|
||||
}
|
||||
(FnKind::AssocTraitImpl, FnKind::AssocTrait) => build_predicates(
|
||||
tcx,
|
||||
sig_id,
|
||||
Some(tcx.parent(def_id.into())),
|
||||
InheritanceKind::Own,
|
||||
args,
|
||||
),
|
||||
|
||||
(FnKind::AssocInherentImpl, FnKind::AssocTrait)
|
||||
| (FnKind::AssocTrait, FnKind::AssocTrait)
|
||||
| (FnKind::AssocInherentImpl, FnKind::Free)
|
||||
| (FnKind::AssocTrait, FnKind::Free) => {
|
||||
builder
|
||||
.with_parent(tcx.parent(def_id.into()))
|
||||
.build()
|
||||
}
|
||||
| (FnKind::AssocTrait, FnKind::Free) => build_predicates(
|
||||
tcx,
|
||||
sig_id,
|
||||
Some(tcx.parent(def_id.into())),
|
||||
InheritanceKind::WithParent(false),
|
||||
args,
|
||||
),
|
||||
|
||||
// For trait impl's `sig_id` is always equal to the corresponding trait method.
|
||||
// For inherent methods delegation is not yet supported.
|
||||
(FnKind::AssocTraitImpl, _)
|
||||
| (_, FnKind::AssocTraitImpl)
|
||||
// Delegation to inherent methods is not yet supported.
|
||||
| (_, FnKind::AssocInherentImpl) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -495,6 +495,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
.iter()
|
||||
.any(|constraint| constraint.ident.name == item.name)
|
||||
})
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.map(|item| self.tcx.item_ident(item.def_id).to_string())
|
||||
.collect()
|
||||
} else {
|
||||
|
|
|
@ -273,7 +273,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
|
|||
|
||||
// We lower to an infer even when the feature gate is not enabled
|
||||
// as it is useful for diagnostics to be able to see a `ConstKind::Infer`
|
||||
args.push(ctx.provided_kind(&args, param, arg));
|
||||
args.push(ctx.provided_kind(param, arg));
|
||||
args_iter.next();
|
||||
params.next();
|
||||
}
|
||||
|
|
|
@ -296,7 +296,6 @@ pub trait GenericArgsLowerer<'a, 'tcx> {
|
|||
|
||||
fn provided_kind(
|
||||
&mut self,
|
||||
preceding_args: &[ty::GenericArg<'tcx>],
|
||||
param: &ty::GenericParamDef,
|
||||
arg: &GenericArg<'tcx>,
|
||||
) -> ty::GenericArg<'tcx>;
|
||||
|
@ -480,7 +479,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
fn provided_kind(
|
||||
&mut self,
|
||||
_preceding_args: &[ty::GenericArg<'tcx>],
|
||||
param: &ty::GenericParamDef,
|
||||
arg: &GenericArg<'tcx>,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
//! impl<T, I: Iterator<Item=T>> SpecExtend<T> for I { /* default impl */ }
|
||||
//! ```
|
||||
//!
|
||||
//! We get that the generic pamameters for `impl2` are `[T, std::vec::IntoIter<T>]`.
|
||||
//! We get that the generic parameters for `impl2` are `[T, std::vec::IntoIter<T>]`.
|
||||
//! `T` is constrained to be `<I as Iterator>::Item`, so we check only
|
||||
//! `std::vec::IntoIter<T>` for repeated parameters, which it doesn't have. The
|
||||
//! predicates of `impl1` are only `T: Sized`, which is also a predicate of
|
||||
|
@ -119,7 +119,6 @@ fn check_always_applicable(
|
|||
impl2_node: Node,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let span = tcx.def_span(impl1_def_id);
|
||||
let mut res = check_has_items(tcx, impl1_def_id, impl2_node, span);
|
||||
|
||||
let (impl1_args, impl2_args) = get_impl_args(tcx, impl1_def_id, impl2_node)?;
|
||||
let impl2_def_id = impl2_node.def_id();
|
||||
|
@ -131,11 +130,10 @@ fn check_always_applicable(
|
|||
unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args)
|
||||
};
|
||||
|
||||
res = res.and(check_static_lifetimes(tcx, &parent_args, span));
|
||||
res = res.and(check_duplicate_params(tcx, impl1_args, parent_args, span));
|
||||
res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span));
|
||||
|
||||
res
|
||||
check_has_items(tcx, impl1_def_id, impl2_node, span)
|
||||
.and(check_static_lifetimes(tcx, &parent_args, span))
|
||||
.and(check_duplicate_params(tcx, impl1_args, parent_args, span))
|
||||
.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span))
|
||||
}
|
||||
|
||||
fn check_has_items(
|
||||
|
|
|
@ -83,12 +83,11 @@ pub mod autoderef;
|
|||
mod bounds;
|
||||
mod check_unused;
|
||||
mod coherence;
|
||||
mod delegation;
|
||||
pub mod hir_ty_lowering;
|
||||
// FIXME: This module shouldn't be public.
|
||||
pub mod collect;
|
||||
mod collect;
|
||||
mod constrained_generic_params;
|
||||
mod delegation;
|
||||
mod errors;
|
||||
pub mod hir_ty_lowering;
|
||||
pub mod hir_wf_check;
|
||||
mod impl_wf_check;
|
||||
mod outlives;
|
||||
|
@ -104,7 +103,8 @@ use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
|||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use self::hir_ty_lowering::{FeedConstTy, HirTyLowerer};
|
||||
pub use crate::collect::suggest_impl_trait;
|
||||
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer};
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
|
@ -152,11 +152,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
});
|
||||
|
||||
if tcx.features().rustc_attrs() {
|
||||
tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx));
|
||||
tcx.sess.time("variance_dumping", || variance::dump::variances(tcx));
|
||||
collect::dump::opaque_hidden_types(tcx);
|
||||
collect::dump::predicates_and_item_bounds(tcx);
|
||||
collect::dump::def_parents(tcx);
|
||||
tcx.sess.time("dumping_rustc_attr_data", || {
|
||||
outlives::dump::inferred_outlives(tcx);
|
||||
variance::dump::variances(tcx);
|
||||
collect::dump::opaque_hidden_types(tcx);
|
||||
collect::dump::predicates_and_item_bounds(tcx);
|
||||
collect::dump::def_parents(tcx);
|
||||
collect::dump::vtables(tcx);
|
||||
});
|
||||
}
|
||||
|
||||
// Make sure we evaluate all static and (non-associated) const items, even if unused.
|
||||
|
|
|
@ -24,7 +24,7 @@ pub(super) fn infer_predicates(
|
|||
|
||||
// If new predicates were added then we need to re-calculate
|
||||
// all crates since there could be new implied predicates.
|
||||
'outer: loop {
|
||||
loop {
|
||||
let mut predicates_added = false;
|
||||
|
||||
// Visit all the crates and infer predicates
|
||||
|
@ -90,7 +90,7 @@ pub(super) fn infer_predicates(
|
|||
}
|
||||
|
||||
if !predicates_added {
|
||||
break 'outer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,9 +27,6 @@ mod solve;
|
|||
|
||||
pub(crate) mod dump;
|
||||
|
||||
/// Code for transforming variances.
|
||||
mod xform;
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { variances_of, crate_variances, ..*providers };
|
||||
}
|
||||
|
|
|
@ -12,8 +12,26 @@ use tracing::debug;
|
|||
use super::constraints::*;
|
||||
use super::terms::VarianceTerm::*;
|
||||
use super::terms::*;
|
||||
use super::xform::*;
|
||||
|
||||
fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance {
|
||||
// Greatest lower bound of the variance lattice as defined in The Paper:
|
||||
//
|
||||
// *
|
||||
// - +
|
||||
// o
|
||||
match (v1, v2) {
|
||||
(ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant,
|
||||
|
||||
(ty::Covariant, ty::Contravariant) => ty::Invariant,
|
||||
(ty::Contravariant, ty::Covariant) => ty::Invariant,
|
||||
|
||||
(ty::Covariant, ty::Covariant) => ty::Covariant,
|
||||
|
||||
(ty::Contravariant, ty::Contravariant) => ty::Contravariant,
|
||||
|
||||
(x, ty::Bivariant) | (ty::Bivariant, x) => x,
|
||||
}
|
||||
}
|
||||
struct SolveContext<'a, 'tcx> {
|
||||
terms_cx: TermsContext<'a, 'tcx>,
|
||||
constraints: Vec<Constraint<'a>>,
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
use rustc_middle::ty;
|
||||
|
||||
pub(crate) fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance {
|
||||
// Greatest lower bound of the variance lattice as
|
||||
// defined in The Paper:
|
||||
//
|
||||
// *
|
||||
// - +
|
||||
// o
|
||||
match (v1, v2) {
|
||||
(ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant,
|
||||
|
||||
(ty::Covariant, ty::Contravariant) => ty::Invariant,
|
||||
(ty::Contravariant, ty::Covariant) => ty::Invariant,
|
||||
|
||||
(ty::Covariant, ty::Covariant) => ty::Covariant,
|
||||
|
||||
(ty::Contravariant, ty::Contravariant) => ty::Contravariant,
|
||||
|
||||
(x, ty::Bivariant) | (ty::Bivariant, x) => x,
|
||||
}
|
||||
}
|
|
@ -1261,7 +1261,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
fn provided_kind(
|
||||
&mut self,
|
||||
_preceding_args: &[ty::GenericArg<'tcx>],
|
||||
param: &ty::GenericParamDef,
|
||||
arg: &GenericArg<'tcx>,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
|
|
|
@ -1147,6 +1147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Some(self.param_env.and(trace.values)),
|
||||
e,
|
||||
true,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,12 +31,12 @@ use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
|
|||
/// functions, closures, and `const`s, including performing type inference
|
||||
/// with [`InferCtxt`].
|
||||
///
|
||||
/// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures*
|
||||
/// and thus does not perform type inference.
|
||||
/// This is in contrast to `rustc_hir_analysis::collect::ItemCtxt`, which is
|
||||
/// used to type-check item *signatures* and thus does not perform type
|
||||
/// inference.
|
||||
///
|
||||
/// See [`ItemCtxt`]'s docs for more.
|
||||
/// See `ItemCtxt`'s docs for more.
|
||||
///
|
||||
/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
|
||||
/// [`InferCtxt`]: infer::InferCtxt
|
||||
pub(crate) struct FnCtxt<'a, 'tcx> {
|
||||
pub(super) body_id: LocalDefId,
|
||||
|
|
|
@ -12,8 +12,8 @@ use rustc_hir::{
|
|||
GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind,
|
||||
WherePredicateKind, expr_needs_parens,
|
||||
};
|
||||
use rustc_hir_analysis::collect::suggest_impl_trait;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_hir_analysis::suggest_impl_trait;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::span_bug;
|
||||
|
|
|
@ -413,7 +413,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
|
||||
fn provided_kind(
|
||||
&mut self,
|
||||
_preceding_args: &[ty::GenericArg<'tcx>],
|
||||
param: &ty::GenericParamDef,
|
||||
arg: &GenericArg<'tcx>,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
|
|
|
@ -402,6 +402,18 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToTrace<'tcx> for ty::ExistentialTraitRef<'tcx> {
|
||||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(
|
||||
ty::Binder::dummy(a),
|
||||
ty::Binder::dummy(b),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
|
||||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
|
@ -410,3 +422,15 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToTrace<'tcx> for ty::ExistentialProjection<'tcx> {
|
||||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::ExistentialProjection(ExpectedFound::new(
|
||||
ty::Binder::dummy(a),
|
||||
ty::Binder::dummy(b),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ use rustc_parse::{
|
|||
};
|
||||
use rustc_passes::{abi_test, input_stats, layout_test};
|
||||
use rustc_resolve::Resolver;
|
||||
use rustc_session::code_stats::VTableSizeInfo;
|
||||
use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
|
||||
use rustc_session::cstore::Untracked;
|
||||
use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_name};
|
||||
|
@ -989,90 +988,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
|
|||
// we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
|
||||
let _ = tcx.all_diagnostic_items(());
|
||||
});
|
||||
|
||||
if sess.opts.unstable_opts.print_vtable_sizes {
|
||||
let traits = tcx.traits(LOCAL_CRATE);
|
||||
|
||||
for &tr in traits {
|
||||
if !tcx.is_dyn_compatible(tr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = ty::print::with_no_trimmed_paths!(tcx.def_path_str(tr));
|
||||
|
||||
let mut first_dsa = true;
|
||||
|
||||
// Number of vtable entries, if we didn't have upcasting
|
||||
let mut entries_ignoring_upcasting = 0;
|
||||
// Number of vtable entries needed solely for upcasting
|
||||
let mut entries_for_upcasting = 0;
|
||||
|
||||
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, tr));
|
||||
|
||||
// A slightly edited version of the code in
|
||||
// `rustc_trait_selection::traits::vtable::vtable_entries`, that works without self
|
||||
// type and just counts number of entries.
|
||||
//
|
||||
// Note that this is technically wrong, for traits which have associated types in
|
||||
// supertraits:
|
||||
//
|
||||
// trait A: AsRef<Self::T> + AsRef<()> { type T; }
|
||||
//
|
||||
// Without self type we can't normalize `Self::T`, so we can't know if `AsRef<Self::T>`
|
||||
// and `AsRef<()>` are the same trait, thus we assume that those are different, and
|
||||
// potentially over-estimate how many vtable entries there are.
|
||||
//
|
||||
// Similarly this is wrong for traits that have methods with possibly-impossible bounds.
|
||||
// For example:
|
||||
//
|
||||
// trait B<T> { fn f(&self) where T: Copy; }
|
||||
//
|
||||
// Here `dyn B<u8>` will have 4 entries, while `dyn B<String>` will only have 3.
|
||||
// However, since we don't know `T`, we can't know if `T: Copy` holds or not,
|
||||
// thus we lean on the bigger side and say it has 4 entries.
|
||||
traits::vtable::prepare_vtable_segments(tcx, trait_ref, |segment| {
|
||||
match segment {
|
||||
traits::vtable::VtblSegment::MetadataDSA => {
|
||||
// If this is the first dsa, it would be included either way,
|
||||
// otherwise it's needed for upcasting
|
||||
if std::mem::take(&mut first_dsa) {
|
||||
entries_ignoring_upcasting += 3;
|
||||
} else {
|
||||
entries_for_upcasting += 3;
|
||||
}
|
||||
}
|
||||
|
||||
traits::vtable::VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
|
||||
// Lookup the shape of vtable for the trait.
|
||||
let own_existential_entries =
|
||||
tcx.own_existential_vtable_entries(trait_ref.def_id());
|
||||
|
||||
// The original code here ignores the method if its predicates are
|
||||
// impossible. We can't really do that as, for example, all not trivial
|
||||
// bounds on generic parameters are impossible (since we don't know the
|
||||
// parameters...), see the comment above.
|
||||
entries_ignoring_upcasting += own_existential_entries.len();
|
||||
|
||||
if emit_vptr {
|
||||
entries_for_upcasting += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ops::ControlFlow::Continue::<std::convert::Infallible>(())
|
||||
});
|
||||
|
||||
sess.code_stats.record_vtable_size(tr, &name, VTableSizeInfo {
|
||||
trait_name: name.clone(),
|
||||
entries: entries_ignoring_upcasting + entries_for_upcasting,
|
||||
entries_ignoring_upcasting,
|
||||
entries_for_upcasting,
|
||||
upcasting_cost_percent: entries_for_upcasting as f64
|
||||
/ entries_ignoring_upcasting as f64
|
||||
* 100.,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
|
||||
|
@ -1153,12 +1068,6 @@ pub(crate) fn start_codegen<'tcx>(
|
|||
tcx.sess.code_stats.print_type_sizes();
|
||||
}
|
||||
|
||||
if tcx.sess.opts.unstable_opts.print_vtable_sizes {
|
||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
|
||||
tcx.sess.code_stats.print_vtable_sizes(crate_name);
|
||||
}
|
||||
|
||||
codegen
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,12 @@ use rustc_data_structures::profiling::TimePassesFormat;
|
|||
use rustc_errors::emitter::HumanReadableErrorType;
|
||||
use rustc_errors::{ColorConfig, registry};
|
||||
use rustc_session::config::{
|
||||
BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel, CoverageOptions,
|
||||
DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
|
||||
FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay,
|
||||
LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig,
|
||||
OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes,
|
||||
PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath,
|
||||
AutoDiff, BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel,
|
||||
CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation,
|
||||
Externs, FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage,
|
||||
InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans,
|
||||
NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
|
||||
Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath,
|
||||
SymbolManglingVersion, WasiExecModel, build_configuration, build_session_options,
|
||||
rustc_optgroups,
|
||||
};
|
||||
|
@ -760,6 +760,7 @@ fn test_unstable_options_tracking_hash() {
|
|||
tracked!(allow_features, Some(vec![String::from("lang_items")]));
|
||||
tracked!(always_encode_mir, true);
|
||||
tracked!(assume_incomplete_release, true);
|
||||
tracked!(autodiff, vec![AutoDiff::Print]);
|
||||
tracked!(binary_dep_depinfo, true);
|
||||
tracked!(box_noalias, false);
|
||||
tracked!(
|
||||
|
|
|
@ -37,7 +37,7 @@ declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTAB
|
|||
impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
let def_id = item.owner_id.to_def_id();
|
||||
// NOTE(nbdd0121): use `object_safety_violations` instead of `is_dyn_compatible` because
|
||||
// NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because
|
||||
// the latter will report `where_clause_object_safety` lint.
|
||||
if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind
|
||||
&& cx.tcx.is_dyn_compatible(def_id)
|
||||
|
|
|
@ -319,7 +319,11 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
|
|||
case LLVMRustAttributeKind::NoAlias:
|
||||
return Attribute::NoAlias;
|
||||
case LLVMRustAttributeKind::NoCapture:
|
||||
#if LLVM_VERSION_GE(21, 0)
|
||||
report_fatal_error("NoCapture doesn't exist in LLVM 21");
|
||||
#else
|
||||
return Attribute::NoCapture;
|
||||
#endif
|
||||
case LLVMRustAttributeKind::NoCfCheck:
|
||||
return Attribute::NoCfCheck;
|
||||
case LLVMRustAttributeKind::NoInline:
|
||||
|
@ -431,6 +435,12 @@ extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) {
|
|||
|
||||
extern "C" LLVMAttributeRef
|
||||
LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
|
||||
#if LLVM_VERSION_GE(21, 0)
|
||||
// LLVM 21 replaced the NoCapture attribute with Captures(none).
|
||||
if (RustAttr == LLVMRustAttributeKind::NoCapture) {
|
||||
return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none()));
|
||||
}
|
||||
#endif
|
||||
return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
|
||||
}
|
||||
|
||||
|
@ -667,8 +677,6 @@ extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
|
|||
unwrap<FunctionType>(Ty), StringRef(Constraints, ConstraintsLen)));
|
||||
}
|
||||
|
||||
typedef DIBuilder *LLVMRustDIBuilderRef;
|
||||
|
||||
template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) {
|
||||
return (DIT *)(Ref ? unwrap<MDNode>(Ref) : nullptr);
|
||||
}
|
||||
|
@ -677,12 +685,6 @@ template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) {
|
|||
#define DIArray DINodeArray
|
||||
#define unwrapDI unwrapDIPtr
|
||||
|
||||
// FIXME(Zalathar): This is a temporary typedef to avoid churning dozens of
|
||||
// bindings that are going to be deleted and replaced with their LLVM-C
|
||||
// equivalents, as part of #134009. After that happens, the remaining bindings
|
||||
// can be adjusted to use `LLVMDIFlags` instead of relying on this typedef.
|
||||
typedef LLVMDIFlags LLVMRustDIFlags;
|
||||
|
||||
// Statically assert that `LLVMDIFlags` (C) and `DIFlags` (C++) have the same
|
||||
// layout, at least for the flags we know about. This isn't guaranteed, but is
|
||||
// likely to remain true, and as long as it is true it makes conversions easy.
|
||||
|
@ -955,7 +957,8 @@ extern "C" LLVMValueRef LLVMRustGetLastInstruction(LLVMBasicBlockRef BB) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustEraseInstBefore(LLVMBasicBlockRef bb, LLVMValueRef I) {
|
||||
extern "C" void LLVMRustEraseInstUntilInclusive(LLVMBasicBlockRef bb,
|
||||
LLVMValueRef I) {
|
||||
auto &BB = *unwrap(bb);
|
||||
auto &Inst = *unwrap<Instruction>(I);
|
||||
auto It = BB.begin();
|
||||
|
@ -963,8 +966,6 @@ extern "C" void LLVMRustEraseInstBefore(LLVMBasicBlockRef bb, LLVMValueRef I) {
|
|||
++It;
|
||||
// Make sure we found the Instruction.
|
||||
assert(It != BB.end());
|
||||
// We don't want to erase the instruction itself.
|
||||
It--;
|
||||
// Delete in rev order to ensure no dangling references.
|
||||
while (It != BB.begin()) {
|
||||
auto Prev = std::prev(It);
|
||||
|
@ -994,34 +995,34 @@ extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
|
|||
unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));
|
||||
}
|
||||
|
||||
extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) {
|
||||
return new DIBuilder(*unwrap(M));
|
||||
extern "C" LLVMDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) {
|
||||
return wrap(new DIBuilder(*unwrap(M)));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustDIBuilderDispose(LLVMRustDIBuilderRef Builder) {
|
||||
delete Builder;
|
||||
extern "C" void LLVMRustDIBuilderDispose(LLVMDIBuilderRef Builder) {
|
||||
delete unwrap(Builder);
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustDIBuilderFinalize(LLVMRustDIBuilderRef Builder) {
|
||||
Builder->finalize();
|
||||
extern "C" void LLVMRustDIBuilderFinalize(LLVMDIBuilderRef Builder) {
|
||||
unwrap(Builder)->finalize();
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit(
|
||||
LLVMRustDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef,
|
||||
LLVMDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef,
|
||||
const char *Producer, size_t ProducerLen, bool isOptimized,
|
||||
const char *Flags, unsigned RuntimeVer, const char *SplitName,
|
||||
size_t SplitNameLen, LLVMRustDebugEmissionKind Kind, uint64_t DWOId,
|
||||
bool SplitDebugInlining, LLVMRustDebugNameTableKind TableKind) {
|
||||
auto *File = unwrapDI<DIFile>(FileRef);
|
||||
|
||||
return wrap(Builder->createCompileUnit(
|
||||
return wrap(unwrap(Builder)->createCompileUnit(
|
||||
Lang, File, StringRef(Producer, ProducerLen), isOptimized, Flags,
|
||||
RuntimeVer, StringRef(SplitName, SplitNameLen), fromRust(Kind), DWOId,
|
||||
SplitDebugInlining, false, fromRust(TableKind)));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename,
|
||||
LLVMRustDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename,
|
||||
size_t FilenameLen, const char *Directory,
|
||||
size_t DirectoryLen, LLVMRustChecksumKind CSKind,
|
||||
const char *Checksum, size_t ChecksumLen,
|
||||
|
@ -1034,29 +1035,29 @@ LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename,
|
|||
std::optional<StringRef> oSource{};
|
||||
if (Source)
|
||||
oSource = StringRef(Source, SourceLen);
|
||||
return wrap(Builder->createFile(StringRef(Filename, FilenameLen),
|
||||
StringRef(Directory, DirectoryLen), CSInfo,
|
||||
oSource));
|
||||
return wrap(unwrap(Builder)->createFile(StringRef(Filename, FilenameLen),
|
||||
StringRef(Directory, DirectoryLen),
|
||||
CSInfo, oSource));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderCreateSubroutineType(LLVMRustDIBuilderRef Builder,
|
||||
LLVMRustDIBuilderCreateSubroutineType(LLVMDIBuilderRef Builder,
|
||||
LLVMMetadataRef ParameterTypes) {
|
||||
return wrap(Builder->createSubroutineType(
|
||||
return wrap(unwrap(Builder)->createSubroutineType(
|
||||
DITypeRefArray(unwrap<MDTuple>(ParameterTypes))));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
|
||||
LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
|
||||
unsigned ScopeLine, LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags,
|
||||
unsigned ScopeLine, LLVMDIFlags Flags, LLVMRustDISPFlags SPFlags,
|
||||
LLVMValueRef MaybeFn, LLVMMetadataRef TParam, LLVMMetadataRef Decl) {
|
||||
DITemplateParameterArray TParams =
|
||||
DITemplateParameterArray(unwrap<MDTuple>(TParam));
|
||||
DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags);
|
||||
DINode::DIFlags llvmFlags = fromRust(Flags);
|
||||
DISubprogram *Sub = Builder->createFunction(
|
||||
DISubprogram *Sub = unwrap(Builder)->createFunction(
|
||||
unwrapDI<DIScope>(Scope), StringRef(Name, NameLen),
|
||||
StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo,
|
||||
unwrapDI<DISubroutineType>(Ty), ScopeLine, llvmFlags, llvmSPFlags,
|
||||
|
@ -1067,15 +1068,15 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
|
|||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
|
||||
LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
|
||||
LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) {
|
||||
LLVMDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) {
|
||||
DITemplateParameterArray TParams =
|
||||
DITemplateParameterArray(unwrap<MDTuple>(TParam));
|
||||
DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags);
|
||||
DINode::DIFlags llvmFlags = fromRust(Flags);
|
||||
DISubprogram *Sub = Builder->createMethod(
|
||||
DISubprogram *Sub = unwrap(Builder)->createMethod(
|
||||
unwrapDI<DIScope>(Scope), StringRef(Name, NameLen),
|
||||
StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo,
|
||||
unwrapDI<DISubroutineType>(Ty), 0, 0,
|
||||
|
@ -1085,39 +1086,39 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod(
|
|||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name,
|
||||
LLVMRustDIBuilderCreateBasicType(LLVMDIBuilderRef Builder, const char *Name,
|
||||
size_t NameLen, uint64_t SizeInBits,
|
||||
unsigned Encoding) {
|
||||
return wrap(
|
||||
Builder->createBasicType(StringRef(Name, NameLen), SizeInBits, Encoding));
|
||||
return wrap(unwrap(Builder)->createBasicType(StringRef(Name, NameLen),
|
||||
SizeInBits, Encoding));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderCreateTypedef(LLVMRustDIBuilderRef Builder,
|
||||
LLVMMetadataRef Type, const char *Name,
|
||||
size_t NameLen, LLVMMetadataRef File,
|
||||
unsigned LineNo, LLVMMetadataRef Scope) {
|
||||
return wrap(Builder->createTypedef(
|
||||
LLVMRustDIBuilderCreateTypedef(LLVMDIBuilderRef Builder, LLVMMetadataRef Type,
|
||||
const char *Name, size_t NameLen,
|
||||
LLVMMetadataRef File, unsigned LineNo,
|
||||
LLVMMetadataRef Scope) {
|
||||
return wrap(unwrap(Builder)->createTypedef(
|
||||
unwrap<DIType>(Type), StringRef(Name, NameLen), unwrap<DIFile>(File),
|
||||
LineNo, unwrapDIPtr<DIScope>(Scope)));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef PointeeTy,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, unsigned AddressSpace,
|
||||
const char *Name, size_t NameLen) {
|
||||
return wrap(Builder->createPointerType(unwrapDI<DIType>(PointeeTy),
|
||||
SizeInBits, AlignInBits, AddressSpace,
|
||||
StringRef(Name, NameLen)));
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef PointeeTy, uint64_t SizeInBits,
|
||||
uint32_t AlignInBits, unsigned AddressSpace, const char *Name,
|
||||
size_t NameLen) {
|
||||
return wrap(unwrap(Builder)->createPointerType(
|
||||
unwrapDI<DIType>(PointeeTy), SizeInBits, AlignInBits, AddressSpace,
|
||||
StringRef(Name, NameLen)));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags,
|
||||
LLVMMetadataRef DerivedFrom, LLVMMetadataRef Elements, unsigned RunTimeLang,
|
||||
LLVMMetadataRef VTableHolder, const char *UniqueId, size_t UniqueIdLen) {
|
||||
return wrap(Builder->createStructType(
|
||||
return wrap(unwrap(Builder)->createStructType(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
|
||||
unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits,
|
||||
fromRust(Flags), unwrapDI<DIType>(DerivedFrom),
|
||||
|
@ -1126,12 +1127,12 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType(
|
|||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags,
|
||||
LLVMMetadataRef Discriminator, LLVMMetadataRef Elements,
|
||||
const char *UniqueId, size_t UniqueIdLen) {
|
||||
return wrap(Builder->createVariantPart(
|
||||
return wrap(unwrap(Builder)->createVariantPart(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
|
||||
unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits,
|
||||
fromRust(Flags), unwrapDI<DIDerivedType>(Discriminator),
|
||||
|
@ -1140,36 +1141,36 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
|
|||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
|
||||
uint32_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags,
|
||||
uint32_t AlignInBits, uint64_t OffsetInBits, LLVMDIFlags Flags,
|
||||
LLVMMetadataRef Ty) {
|
||||
return wrap(Builder->createMemberType(
|
||||
return wrap(unwrap(Builder)->createMemberType(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
|
||||
unwrapDI<DIFile>(File), LineNo, SizeInBits, AlignInBits, OffsetInBits,
|
||||
fromRust(Flags), unwrapDI<DIType>(Ty)));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
|
||||
uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant,
|
||||
LLVMRustDIFlags Flags, LLVMMetadataRef Ty) {
|
||||
LLVMDIFlags Flags, LLVMMetadataRef Ty) {
|
||||
llvm::ConstantInt *D = nullptr;
|
||||
if (Discriminant) {
|
||||
D = unwrap<llvm::ConstantInt>(Discriminant);
|
||||
}
|
||||
return wrap(Builder->createVariantMemberType(
|
||||
return wrap(unwrap(Builder)->createVariantMemberType(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
|
||||
unwrapDI<DIFile>(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, D,
|
||||
fromRust(Flags), unwrapDI<DIType>(Ty)));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
|
||||
LLVMRustDIFlags Flags, LLVMValueRef val, uint32_t AlignInBits) {
|
||||
return wrap(Builder->createStaticMemberType(
|
||||
LLVMDIFlags Flags, LLVMValueRef val, uint32_t AlignInBits) {
|
||||
return wrap(unwrap(Builder)->createStaticMemberType(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
|
||||
unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), fromRust(Flags),
|
||||
unwrap<llvm::ConstantInt>(val), llvm::dwarf::DW_TAG_member, AlignInBits));
|
||||
|
@ -1183,21 +1184,21 @@ LLVMRustDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag,
|
|||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderCreateLexicalBlock(LLVMRustDIBuilderRef Builder,
|
||||
LLVMRustDIBuilderCreateLexicalBlock(LLVMDIBuilderRef Builder,
|
||||
LLVMMetadataRef Scope, LLVMMetadataRef File,
|
||||
unsigned Line, unsigned Col) {
|
||||
return wrap(Builder->createLexicalBlock(unwrapDI<DIDescriptor>(Scope),
|
||||
unwrapDI<DIFile>(File), Line, Col));
|
||||
return wrap(unwrap(Builder)->createLexicalBlock(
|
||||
unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(File), Line, Col));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlockFile(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File) {
|
||||
return wrap(Builder->createLexicalBlockFile(unwrapDI<DIDescriptor>(Scope),
|
||||
unwrapDI<DIFile>(File)));
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File) {
|
||||
return wrap(unwrap(Builder)->createLexicalBlockFile(
|
||||
unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(File)));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name,
|
||||
size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
|
||||
LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
|
||||
bool IsLocalToUnit, LLVMValueRef V, LLVMMetadataRef Decl = nullptr,
|
||||
|
@ -1206,16 +1207,16 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
|
|||
|
||||
llvm::DIExpression *InitExpr = nullptr;
|
||||
if (llvm::ConstantInt *IntVal = llvm::dyn_cast<llvm::ConstantInt>(InitVal)) {
|
||||
InitExpr = Builder->createConstantValueExpression(
|
||||
InitExpr = unwrap(Builder)->createConstantValueExpression(
|
||||
IntVal->getValue().getSExtValue());
|
||||
} else if (llvm::ConstantFP *FPVal =
|
||||
llvm::dyn_cast<llvm::ConstantFP>(InitVal)) {
|
||||
InitExpr = Builder->createConstantValueExpression(
|
||||
InitExpr = unwrap(Builder)->createConstantValueExpression(
|
||||
FPVal->getValueAPF().bitcastToAPInt().getZExtValue());
|
||||
}
|
||||
|
||||
llvm::DIGlobalVariableExpression *VarExpr =
|
||||
Builder->createGlobalVariableExpression(
|
||||
unwrap(Builder)->createGlobalVariableExpression(
|
||||
unwrapDI<DIDescriptor>(Context), StringRef(Name, NameLen),
|
||||
StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File),
|
||||
LineNo, unwrapDI<DIType>(Ty), IsLocalToUnit,
|
||||
|
@ -1228,17 +1229,17 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
|
|||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
|
||||
LLVMRustDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope,
|
||||
LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope,
|
||||
const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo,
|
||||
LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMRustDIFlags Flags,
|
||||
unsigned ArgNo, uint32_t AlignInBits) {
|
||||
LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMDIFlags Flags, unsigned ArgNo,
|
||||
uint32_t AlignInBits) {
|
||||
if (Tag == 0x100) { // DW_TAG_auto_variable
|
||||
return wrap(Builder->createAutoVariable(
|
||||
return wrap(unwrap(Builder)->createAutoVariable(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
|
||||
unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve,
|
||||
fromRust(Flags), AlignInBits));
|
||||
} else {
|
||||
return wrap(Builder->createParameterVariable(
|
||||
return wrap(unwrap(Builder)->createParameterVariable(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ArgNo,
|
||||
unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve,
|
||||
fromRust(Flags)));
|
||||
|
@ -1246,53 +1247,56 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
|
|||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderCreateArrayType(LLVMRustDIBuilderRef Builder, uint64_t Size,
|
||||
LLVMRustDIBuilderCreateArrayType(LLVMDIBuilderRef Builder, uint64_t Size,
|
||||
uint32_t AlignInBits, LLVMMetadataRef Ty,
|
||||
LLVMMetadataRef Subscripts) {
|
||||
return wrap(
|
||||
Builder->createArrayType(Size, AlignInBits, unwrapDI<DIType>(Ty),
|
||||
DINodeArray(unwrapDI<MDTuple>(Subscripts))));
|
||||
return wrap(unwrap(Builder)->createArrayType(
|
||||
Size, AlignInBits, unwrapDI<DIType>(Ty),
|
||||
DINodeArray(unwrapDI<MDTuple>(Subscripts))));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderGetOrCreateSubrange(LLVMRustDIBuilderRef Builder, int64_t Lo,
|
||||
LLVMRustDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo,
|
||||
int64_t Count) {
|
||||
return wrap(Builder->getOrCreateSubrange(Lo, Count));
|
||||
return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder,
|
||||
LLVMRustDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder,
|
||||
LLVMMetadataRef *Ptr, unsigned Count) {
|
||||
Metadata **DataValue = unwrap(Ptr);
|
||||
return wrap(
|
||||
Builder->getOrCreateArray(ArrayRef<Metadata *>(DataValue, Count)).get());
|
||||
return wrap(unwrap(Builder)
|
||||
->getOrCreateArray(ArrayRef<Metadata *>(DataValue, Count))
|
||||
.get());
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustDIBuilderInsertDeclareAtEnd(
|
||||
LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo,
|
||||
uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
|
||||
LLVMBasicBlockRef InsertAtEnd) {
|
||||
Builder->insertDeclare(unwrap(V), unwrap<DILocalVariable>(VarInfo),
|
||||
Builder->createExpression(
|
||||
llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
|
||||
DebugLoc(cast<MDNode>(unwrap(DL))),
|
||||
unwrap(InsertAtEnd));
|
||||
extern "C" void
|
||||
LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V,
|
||||
LLVMMetadataRef VarInfo, uint64_t *AddrOps,
|
||||
unsigned AddrOpsCount, LLVMMetadataRef DL,
|
||||
LLVMBasicBlockRef InsertAtEnd) {
|
||||
unwrap(Builder)->insertDeclare(
|
||||
unwrap(V), unwrap<DILocalVariable>(VarInfo),
|
||||
unwrap(Builder)->createExpression(
|
||||
llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
|
||||
DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator(
|
||||
LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen,
|
||||
const uint64_t Value[2], unsigned SizeInBits, bool IsUnsigned) {
|
||||
return wrap(Builder->createEnumerator(
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name,
|
||||
size_t NameLen, const uint64_t Value[2],
|
||||
unsigned SizeInBits, bool IsUnsigned) {
|
||||
return wrap(unwrap(Builder)->createEnumerator(
|
||||
StringRef(Name, NameLen),
|
||||
APSInt(APInt(SizeInBits, ArrayRef<uint64_t>(Value, 2)), IsUnsigned)));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, LLVMMetadataRef Elements,
|
||||
LLVMMetadataRef ClassTy, bool IsScoped) {
|
||||
return wrap(Builder->createEnumerationType(
|
||||
return wrap(unwrap(Builder)->createEnumerationType(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
|
||||
unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits,
|
||||
DINodeArray(unwrapDI<MDTuple>(Elements)), unwrapDI<DIType>(ClassTy),
|
||||
|
@ -1300,12 +1304,12 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType(
|
|||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags,
|
||||
LLVMMetadataRef Elements, unsigned RunTimeLang, const char *UniqueId,
|
||||
size_t UniqueIdLen) {
|
||||
return wrap(Builder->createUnionType(
|
||||
return wrap(unwrap(Builder)->createUnionType(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
|
||||
unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits,
|
||||
fromRust(Flags), DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang,
|
||||
|
@ -1313,28 +1317,28 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(
|
|||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, LLVMMetadataRef Ty) {
|
||||
bool IsDefault = false; // FIXME: should we ever set this true?
|
||||
return wrap(Builder->createTemplateTypeParameter(
|
||||
return wrap(unwrap(Builder)->createTemplateTypeParameter(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
|
||||
unwrapDI<DIType>(Ty), IsDefault));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderCreateNameSpace(LLVMRustDIBuilderRef Builder,
|
||||
LLVMRustDIBuilderCreateNameSpace(LLVMDIBuilderRef Builder,
|
||||
LLVMMetadataRef Scope, const char *Name,
|
||||
size_t NameLen, bool ExportSymbols) {
|
||||
return wrap(Builder->createNameSpace(
|
||||
return wrap(unwrap(Builder)->createNameSpace(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ExportSymbols));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustDICompositeTypeReplaceArrays(
|
||||
LLVMRustDIBuilderRef Builder, LLVMMetadataRef CompositeTy,
|
||||
LLVMDIBuilderRef Builder, LLVMMetadataRef CompositeTy,
|
||||
LLVMMetadataRef Elements, LLVMMetadataRef Params) {
|
||||
DICompositeType *Tmp = unwrapDI<DICompositeType>(CompositeTy);
|
||||
Builder->replaceArrays(Tmp, DINodeArray(unwrap<MDTuple>(Elements)),
|
||||
DINodeArray(unwrap<MDTuple>(Params)));
|
||||
unwrap(Builder)->replaceArrays(Tmp, DINodeArray(unwrap<MDTuple>(Elements)),
|
||||
DINodeArray(unwrap<MDTuple>(Params)));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
|
|
|
@ -9,6 +9,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
|||
use rustc_data_structures::memmap::{Mmap, MmapMut};
|
||||
use rustc_data_structures::sync::{Lrc, join, par_for_each_in};
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_data_structures::thousands::format_with_underscores;
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet};
|
||||
|
@ -22,7 +23,6 @@ use rustc_middle::traits::specialization_graph;
|
|||
use rustc_middle::ty::codec::TyEncoder;
|
||||
use rustc_middle::ty::fast_reject::{self, TreatParams};
|
||||
use rustc_middle::ty::{AssocItemContainer, SymbolName};
|
||||
use rustc_middle::util::common::to_readable_str;
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque};
|
||||
use rustc_session::config::{CrateType, OptLevel};
|
||||
|
@ -782,7 +782,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
"{} {:<23}{:>10} ({:4.1}%)",
|
||||
prefix,
|
||||
label,
|
||||
to_readable_str(size),
|
||||
format_with_underscores(size),
|
||||
perc(size)
|
||||
);
|
||||
}
|
||||
|
@ -791,7 +791,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
"{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
|
||||
prefix,
|
||||
"Total",
|
||||
to_readable_str(total_bytes),
|
||||
format_with_underscores(total_bytes),
|
||||
perc(zero_bytes)
|
||||
);
|
||||
eprintln!("{prefix}");
|
||||
|
|
|
@ -17,6 +17,9 @@ middle_assert_gen_resume_after_panic = `gen` fn or block cannot be further itera
|
|||
middle_assert_misaligned_ptr_deref =
|
||||
misaligned pointer dereference: address must be a multiple of {$required} but is {$found}
|
||||
|
||||
middle_assert_null_ptr_deref =
|
||||
null pointer dereference occurred
|
||||
|
||||
middle_assert_op_overflow =
|
||||
attempt to compute `{$left} {$op} {$right}`, which would overflow
|
||||
|
||||
|
@ -32,6 +35,8 @@ middle_assert_shl_overflow =
|
|||
middle_assert_shr_overflow =
|
||||
attempt to shift right by `{$val}`, which would overflow
|
||||
|
||||
middle_autodiff_unsafe_inner_const_ref = reading from a `Duplicated` const {$ty} is unsafe
|
||||
|
||||
middle_bounds_check =
|
||||
index out of bounds: the length is {$len} but the index is {$index}
|
||||
|
||||
|
@ -107,6 +112,8 @@ middle_type_length_limit = reached the type-length limit while instantiating `{$
|
|||
middle_unknown_layout =
|
||||
the type `{$ty}` has an unknown layout
|
||||
|
||||
middle_unsupported_union = we don't support unions yet: '{$ty_name}'
|
||||
|
||||
middle_values_too_big =
|
||||
values of the type `{$ty}` are too big for the target architecture
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ macro_rules! arena_types {
|
|||
[] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>,
|
||||
[decode] attribute: rustc_hir::Attribute,
|
||||
[] name_set: rustc_data_structures::unord::UnordSet<rustc_span::Symbol>,
|
||||
[] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem,
|
||||
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::Symbol>,
|
||||
[] pats: rustc_middle::ty::PatternKind<'tcx>,
|
||||
|
||||
|
|
|
@ -37,6 +37,20 @@ pub struct OpaqueHiddenTypeMismatch<'tcx> {
|
|||
pub sub: TypeMismatchReason,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_unsupported_union)]
|
||||
pub struct UnsupportedUnion {
|
||||
pub ty_name: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_autodiff_unsafe_inner_const_ref)]
|
||||
pub struct AutodiffUnsafeInnerConstRef {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum TypeMismatchReason {
|
||||
#[label(middle_conflict_types)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! "Hooks" provide a way for `tcx` functionality to be provided by some downstream crate without
|
||||
//! everything in rustc having to depend on that crate. This is somewhat similar to queries, but
|
||||
//! queries come with a lot of machinery for caching and incremental compilation, whereas hooks are
|
||||
//! just plain function pointers without any of the query magic.
|
||||
//! "Hooks" let you write `tcx` methods in downstream crates and call them in this crate, reducing
|
||||
//! the amount of code that needs to be in this crate (which is already very big). This is somewhat
|
||||
//! similar to queries, but queries come with a lot of machinery for caching and incremental
|
||||
//! compilation, whereas hooks are just plain function pointers without any of the query magic.
|
||||
|
||||
use rustc_hir::def_id::{DefId, DefPathHash};
|
||||
use rustc_session::StableCrateId;
|
||||
|
@ -75,12 +75,6 @@ declare_hooks! {
|
|||
/// (Eligible functions might nevertheless be skipped for other reasons.)
|
||||
hook is_eligible_for_coverage(key: LocalDefId) -> bool;
|
||||
|
||||
/// Create the MIR for a given `DefId` - this includes
|
||||
/// unreachable code.
|
||||
/// You do not want to call this yourself, instead use the cached version
|
||||
/// via `mir_built`
|
||||
hook build_mir(key: LocalDefId) -> mir::Body<'tcx>;
|
||||
|
||||
/// Imports all `SourceFile`s from the given crate into the current session.
|
||||
/// This normally happens automatically when we decode a `Span` from
|
||||
/// that crate's metadata - however, the incr comp cache needs
|
||||
|
@ -99,14 +93,11 @@ declare_hooks! {
|
|||
/// Will fetch a DefId from a DefPathHash for a foreign crate.
|
||||
hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> DefId;
|
||||
|
||||
/// Create a THIR tree for debugging.
|
||||
hook thir_tree(key: LocalDefId) -> String;
|
||||
|
||||
/// Create a list-like THIR representation for debugging.
|
||||
hook thir_flat(key: LocalDefId) -> String;
|
||||
|
||||
/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
|
||||
/// can just link to the upstream crate and therefore don't need a mono item.
|
||||
///
|
||||
/// Note: this hook isn't called within `rustc_middle` but #127779 suggests it's a hook instead
|
||||
/// of a normal function because external tools might want to override it.
|
||||
hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool;
|
||||
|
||||
hook alloc_self_profile_query_strings() -> ();
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
///
|
||||
/// If you have a span available, you should use [`span_bug`] instead.
|
||||
///
|
||||
/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`]
|
||||
/// may be useful.
|
||||
/// If the bug should only be emitted when compilation didn't fail,
|
||||
/// [`DiagCtxtHandle::span_delayed_bug`] may be useful.
|
||||
///
|
||||
/// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug
|
||||
/// [`span_bug`]: crate::span_bug
|
||||
|
@ -14,14 +14,8 @@ macro_rules! bug {
|
|||
() => (
|
||||
$crate::bug!("impossible case reached")
|
||||
);
|
||||
($msg:expr) => (
|
||||
$crate::util::bug::bug_fmt(::std::format_args!($msg))
|
||||
);
|
||||
($msg:expr,) => (
|
||||
$crate::bug!($msg)
|
||||
);
|
||||
($fmt:expr, $($arg:tt)+) => (
|
||||
$crate::util::bug::bug_fmt(::std::format_args!($fmt, $($arg)+))
|
||||
($($arg:tt)+) => (
|
||||
$crate::util::bug::bug_fmt(::std::format_args!($($arg)+))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -30,20 +24,14 @@ macro_rules! bug {
|
|||
/// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger
|
||||
/// ICEs.
|
||||
///
|
||||
/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`]
|
||||
/// may be useful.
|
||||
/// If the bug should only be emitted when compilation didn't fail,
|
||||
/// [`DiagCtxtHandle::span_delayed_bug`] may be useful.
|
||||
///
|
||||
/// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug
|
||||
#[macro_export]
|
||||
macro_rules! span_bug {
|
||||
($span:expr, $msg:expr) => (
|
||||
$crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg))
|
||||
);
|
||||
($span:expr, $msg:expr,) => (
|
||||
$crate::span_bug!($span, $msg)
|
||||
);
|
||||
($span:expr, $fmt:expr, $($arg:tt)+) => (
|
||||
$crate::util::bug::span_bug_fmt($span, ::std::format_args!($fmt, $($arg)+))
|
||||
($span:expr, $($arg:tt)+) => (
|
||||
$crate::util::bug::span_bug_fmt($span, ::std::format_args!($($arg)+))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -53,7 +41,6 @@ macro_rules! span_bug {
|
|||
// When possible, use one of these (relatively) convenient macros to write
|
||||
// the impls for you.
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! TrivialLiftImpls {
|
||||
($($ty:ty),+ $(,)?) => {
|
||||
$(
|
||||
|
@ -69,7 +56,6 @@ macro_rules! TrivialLiftImpls {
|
|||
|
||||
/// Used for types that are `Copy` and which **do not care about arena
|
||||
/// allocated data** (i.e., don't need to be folded).
|
||||
#[macro_export]
|
||||
macro_rules! TrivialTypeTraversalImpls {
|
||||
($($ty:ty),+ $(,)?) => {
|
||||
$(
|
||||
|
@ -104,7 +90,6 @@ macro_rules! TrivialTypeTraversalImpls {
|
|||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! TrivialTypeTraversalAndLiftImpls {
|
||||
($($t:tt)*) => {
|
||||
TrivialTypeTraversalImpls! { $($t)* }
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_abi::Align;
|
||||
use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs;
|
||||
use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use rustc_span::Symbol;
|
||||
|
@ -52,6 +53,8 @@ pub struct CodegenFnAttrs {
|
|||
/// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
|
||||
/// the function entry.
|
||||
pub patchable_function_entry: Option<PatchableFunctionEntry>,
|
||||
/// For the `#[autodiff]` macros.
|
||||
pub autodiff_item: Option<AutoDiffAttrs>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
|
@ -160,6 +163,7 @@ impl CodegenFnAttrs {
|
|||
instruction_set: None,
|
||||
alignment: None,
|
||||
patchable_function_entry: None,
|
||||
autodiff_item: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,15 +45,22 @@ pub enum ObjectLifetimeDefault {
|
|||
Param(DefId),
|
||||
}
|
||||
|
||||
/// Maps the id of each lifetime reference to the lifetime decl
|
||||
/// Maps the id of each bound variable reference to the variable decl
|
||||
/// that it corresponds to.
|
||||
#[derive(HashStable, Debug)]
|
||||
#[derive(Debug, Default, HashStable)]
|
||||
pub struct ResolveBoundVars {
|
||||
/// Maps from every use of a named (not anonymous) lifetime to a
|
||||
/// `Region` describing how that region is bound
|
||||
// Maps from every use of a named (not anonymous) bound var to a
|
||||
// `ResolvedArg` describing how that variable is bound.
|
||||
pub defs: SortedMap<ItemLocalId, ResolvedArg>,
|
||||
|
||||
// Maps relevant hir items to the bound vars on them. These include:
|
||||
// - function defs
|
||||
// - function pointers
|
||||
// - closures
|
||||
// - trait refs
|
||||
// - bound types (like `T` in `for<'a> T<'a>: Foo`)
|
||||
pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>,
|
||||
|
||||
// List captured variables for each opaque type.
|
||||
pub opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>,
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisit
|
|||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||
use tracing::trace;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
pub use self::query::*;
|
||||
use self::visit::TyContext;
|
||||
|
@ -1796,6 +1796,47 @@ impl DefLocation {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if the specified `local` is used as the `self` parameter of a method call
|
||||
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
|
||||
/// returned.
|
||||
pub fn find_self_call<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local: Local,
|
||||
block: BasicBlock,
|
||||
) -> Option<(DefId, GenericArgsRef<'tcx>)> {
|
||||
debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator);
|
||||
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
|
||||
&body[block].terminator
|
||||
&& let Operand::Constant(box ConstOperand { const_, .. }) = func
|
||||
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
|
||||
&& let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
||||
tcx.opt_associated_item(def_id)
|
||||
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
|
||||
**args
|
||||
{
|
||||
if self_place.as_local() == Some(local) {
|
||||
return Some((def_id, fn_args));
|
||||
}
|
||||
|
||||
// Handle the case where `self_place` gets reborrowed.
|
||||
// This happens when the receiver is `&T`.
|
||||
for stmt in &body[block].statements {
|
||||
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind
|
||||
&& let Some(reborrow_local) = place.as_local()
|
||||
&& self_place.as_local() == Some(reborrow_local)
|
||||
&& let Rvalue::Ref(_, _, deref_place) = rvalue
|
||||
&& let PlaceRef { local: deref_local, projection: [ProjectionElem::Deref] } =
|
||||
deref_place.as_ref()
|
||||
&& deref_local == local
|
||||
{
|
||||
return Some((def_id, fn_args));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod size_asserts {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
|
||||
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
|
||||
use rustc_attr_parsing::InlineAttr;
|
||||
use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
|
@ -246,6 +247,7 @@ impl ToStableHashKey<StableHashingContext<'_>> for MonoItem<'_> {
|
|||
pub struct MonoItemPartitions<'tcx> {
|
||||
pub codegen_units: &'tcx [CodegenUnit<'tcx>],
|
||||
pub all_mono_items: &'tcx DefIdSet,
|
||||
pub autodiff_items: &'tcx [AutoDiffItem],
|
||||
}
|
||||
|
||||
#[derive(Debug, HashStable)]
|
||||
|
|
|
@ -1076,6 +1076,7 @@ pub enum AssertKind<O> {
|
|||
ResumedAfterReturn(CoroutineKind),
|
||||
ResumedAfterPanic(CoroutineKind),
|
||||
MisalignedPointerDereference { required: O, found: O },
|
||||
NullPointerDereference,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
|
|
|
@ -206,6 +206,7 @@ impl<O> AssertKind<O> {
|
|||
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
||||
LangItem::PanicGenFnNonePanic
|
||||
}
|
||||
NullPointerDereference => LangItem::PanicNullPointerDereference,
|
||||
|
||||
BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
|
||||
bug!("Unexpected AssertKind")
|
||||
|
@ -271,6 +272,7 @@ impl<O> AssertKind<O> {
|
|||
"\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
|
||||
)
|
||||
}
|
||||
NullPointerDereference => write!(f, "\"null pointer dereference occured\""),
|
||||
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
|
||||
write!(f, "\"coroutine resumed after completion\"")
|
||||
}
|
||||
|
@ -341,7 +343,7 @@ impl<O> AssertKind<O> {
|
|||
ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
|
||||
middle_assert_coroutine_resume_after_panic
|
||||
}
|
||||
|
||||
NullPointerDereference => middle_assert_null_ptr_deref,
|
||||
MisalignedPointerDereference { .. } => middle_assert_misaligned_ptr_deref,
|
||||
}
|
||||
}
|
||||
|
@ -374,7 +376,7 @@ impl<O> AssertKind<O> {
|
|||
add!("left", format!("{left:#?}"));
|
||||
add!("right", format!("{right:#?}"));
|
||||
}
|
||||
ResumedAfterReturn(_) | ResumedAfterPanic(_) => {}
|
||||
ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference => {}
|
||||
MisalignedPointerDereference { required, found } => {
|
||||
add!("required", format!("{required:#?}"));
|
||||
add!("found", format!("{found:#?}"));
|
||||
|
|
|
@ -636,7 +636,7 @@ macro_rules! make_mir_visitor {
|
|||
OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
|
||||
self.visit_operand(op, location);
|
||||
}
|
||||
ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
|
||||
ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference => {
|
||||
// Nothing to visit
|
||||
}
|
||||
MisalignedPointerDereference { required, found } => {
|
||||
|
|
|
@ -95,7 +95,7 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
|
||||
impl<'tcx> Key for (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
|
|
|
@ -1437,9 +1437,9 @@ rustc_queries! {
|
|||
desc { |tcx| "finding all existential vtable entries for trait `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
query vtable_entries(key: ty::PolyTraitRef<'tcx>)
|
||||
query vtable_entries(key: ty::TraitRef<'tcx>)
|
||||
-> &'tcx [ty::VtblEntry<'tcx>] {
|
||||
desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) }
|
||||
desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id) }
|
||||
}
|
||||
|
||||
query first_method_vtable_slot(key: ty::TraitRef<'tcx>) -> usize {
|
||||
|
@ -1451,7 +1451,7 @@ rustc_queries! {
|
|||
key.1, key.0 }
|
||||
}
|
||||
|
||||
query vtable_allocation(key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId {
|
||||
query vtable_allocation(key: (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId {
|
||||
desc { |tcx| "vtable const allocation for <{} as {}>",
|
||||
key.0,
|
||||
key.1.map(|trait_ref| format!("{trait_ref}")).unwrap_or("_".to_owned())
|
||||
|
|
|
@ -428,7 +428,7 @@ pub enum IsConstable {
|
|||
Ctor,
|
||||
}
|
||||
|
||||
crate::TrivialTypeTraversalAndLiftImpls! {
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
IsConstable,
|
||||
}
|
||||
|
||||
|
|
|
@ -858,7 +858,12 @@ where
|
|||
}
|
||||
|
||||
let mk_dyn_vtable = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
|
||||
let min_count = ty::vtable_min_entries(tcx, principal);
|
||||
let min_count = ty::vtable_min_entries(
|
||||
tcx,
|
||||
principal.map(|principal| {
|
||||
tcx.instantiate_bound_regions_with_erased(principal)
|
||||
}),
|
||||
);
|
||||
Ty::new_imm_ref(
|
||||
tcx,
|
||||
tcx.lifetimes.re_static,
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::ty::{self, ExistentialPredicateStableCmpExt, TyCtxt};
|
|||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Given a `def_id` of a trait or impl method, compute whether that method needs to
|
||||
/// have an RPITIT shim applied to it for it to be object safe. If so, return the
|
||||
/// have an RPITIT shim applied to it for it to be dyn compatible. If so, return the
|
||||
/// `def_id` of the RPITIT, and also the args of trait method that returns the RPITIT.
|
||||
///
|
||||
/// NOTE that these args are not, in general, the same as than the RPITIT's args. They
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc_type_ir::elaborate;
|
|||
use crate::mir::interpret::{
|
||||
AllocId, AllocInit, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range,
|
||||
};
|
||||
use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
|
||||
use crate::ty::{self, Instance, TraitRef, Ty, TyCtxt};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, HashStable)]
|
||||
pub enum VtblEntry<'tcx> {
|
||||
|
@ -22,7 +22,7 @@ pub enum VtblEntry<'tcx> {
|
|||
/// dispatchable associated function
|
||||
Method(Instance<'tcx>),
|
||||
/// pointer to a separate supertrait vtable, can be used by trait upcasting coercion
|
||||
TraitVPtr(PolyTraitRef<'tcx>),
|
||||
TraitVPtr(TraitRef<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for VtblEntry<'tcx> {
|
||||
|
@ -59,7 +59,7 @@ pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;
|
|||
// function is an accurate approximation. We verify this when actually computing the vtable below.
|
||||
pub(crate) fn vtable_min_entries<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
|
||||
) -> usize {
|
||||
let mut count = TyCtxt::COMMON_VTABLE_ENTRIES.len();
|
||||
let Some(trait_ref) = trait_ref else {
|
||||
|
@ -67,7 +67,7 @@ pub(crate) fn vtable_min_entries<'tcx>(
|
|||
};
|
||||
|
||||
// This includes self in supertraits.
|
||||
for def_id in elaborate::supertrait_def_ids(tcx, trait_ref.def_id()) {
|
||||
for def_id in elaborate::supertrait_def_ids(tcx, trait_ref.def_id) {
|
||||
count += tcx.own_existential_vtable_entries(def_id).len();
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ pub(crate) fn vtable_min_entries<'tcx>(
|
|||
/// initial contents.)
|
||||
pub(super) fn vtable_allocation_provider<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
|
||||
key: (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>),
|
||||
) -> AllocId {
|
||||
let (ty, poly_trait_ref) = key;
|
||||
|
||||
|
@ -118,7 +118,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
|
|||
|
||||
for (idx, entry) in vtable_entries.iter().enumerate() {
|
||||
let idx: u64 = u64::try_from(idx).unwrap();
|
||||
let scalar = match entry {
|
||||
let scalar = match *entry {
|
||||
VtblEntry::MetadataDropInPlace => {
|
||||
if ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) {
|
||||
let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
|
||||
|
@ -134,13 +134,12 @@ pub(super) fn vtable_allocation_provider<'tcx>(
|
|||
VtblEntry::Vacant => continue,
|
||||
VtblEntry::Method(instance) => {
|
||||
// Prepare the fn ptr we write into the vtable.
|
||||
let fn_alloc_id = tcx.reserve_and_set_fn_alloc(*instance, CTFE_ALLOC_SALT);
|
||||
let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT);
|
||||
let fn_ptr = Pointer::from(fn_alloc_id);
|
||||
Scalar::from_pointer(fn_ptr, &tcx)
|
||||
}
|
||||
VtblEntry::TraitVPtr(trait_ref) => {
|
||||
let super_trait_ref = trait_ref
|
||||
.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
|
||||
let super_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref);
|
||||
let supertrait_alloc_id = tcx.vtable_allocation((ty, Some(super_trait_ref)));
|
||||
let vptr = Pointer::from(supertrait_alloc_id);
|
||||
Scalar::from_pointer(vptr, &tcx)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// These functions are used by macro expansion for bug! and span_bug!
|
||||
// These functions are used by macro expansion for `bug!` and `span_bug!`.
|
||||
|
||||
use std::fmt;
|
||||
use std::panic::{Location, panic_any};
|
||||
|
@ -8,15 +8,15 @@ use rustc_span::Span;
|
|||
|
||||
use crate::ty::{TyCtxt, tls};
|
||||
|
||||
// This wrapper makes for more compact code at callsites than calling `opt_span_buf_fmt` directly.
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
#[track_caller]
|
||||
pub fn bug_fmt(args: fmt::Arguments<'_>) -> ! {
|
||||
// this wrapper mostly exists so I don't have to write a fully
|
||||
// qualified path of None::<Span> inside the bug!() macro definition
|
||||
opt_span_bug_fmt(None::<Span>, args, Location::caller());
|
||||
}
|
||||
|
||||
// This wrapper makes for more compact code at callsites than calling `opt_span_buf_fmt` directly.
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
#[track_caller]
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub fn to_readable_str(mut val: usize) -> String {
|
||||
let mut groups = vec![];
|
||||
loop {
|
||||
let group = val % 1000;
|
||||
|
||||
val /= 1000;
|
||||
|
||||
if val == 0 {
|
||||
groups.push(group.to_string());
|
||||
break;
|
||||
} else {
|
||||
groups.push(format!("{group:03}"));
|
||||
}
|
||||
}
|
||||
|
||||
groups.reverse();
|
||||
|
||||
groups.join("_")
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_readable_str() {
|
||||
assert_eq!("0", to_readable_str(0));
|
||||
assert_eq!("1", to_readable_str(1));
|
||||
assert_eq!("99", to_readable_str(99));
|
||||
assert_eq!("999", to_readable_str(999));
|
||||
assert_eq!("1_000", to_readable_str(1_000));
|
||||
assert_eq!("1_001", to_readable_str(1_001));
|
||||
assert_eq!("999_999", to_readable_str(999_999));
|
||||
assert_eq!("1_000_000", to_readable_str(1_000_000));
|
||||
assert_eq!("1_234_567", to_readable_str(1_234_567));
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::mir::*;
|
||||
use crate::ty::{self, GenericArgsRef, TyCtxt};
|
||||
|
||||
/// Checks if the specified `local` is used as the `self` parameter of a method call
|
||||
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
|
||||
/// returned.
|
||||
pub fn find_self_call<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local: Local,
|
||||
block: BasicBlock,
|
||||
) -> Option<(DefId, GenericArgsRef<'tcx>)> {
|
||||
debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator);
|
||||
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
|
||||
&body[block].terminator
|
||||
&& let Operand::Constant(box ConstOperand { const_, .. }) = func
|
||||
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
|
||||
&& let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
||||
tcx.opt_associated_item(def_id)
|
||||
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
|
||||
**args
|
||||
{
|
||||
if self_place.as_local() == Some(local) {
|
||||
return Some((def_id, fn_args));
|
||||
}
|
||||
|
||||
// Handle the case where `self_place` gets reborrowed.
|
||||
// This happens when the receiver is `&T`.
|
||||
for stmt in &body[block].statements {
|
||||
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind
|
||||
&& let Some(reborrow_local) = place.as_local()
|
||||
&& self_place.as_local() == Some(reborrow_local)
|
||||
&& let Rvalue::Ref(_, _, deref_place) = rvalue
|
||||
&& let PlaceRef { local: deref_local, projection: [ProjectionElem::Deref] } =
|
||||
deref_place.as_ref()
|
||||
&& deref_local == local
|
||||
{
|
||||
return Some((def_id, fn_args));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
|
@ -1,8 +1,4 @@
|
|||
pub mod bug;
|
||||
pub mod common;
|
||||
pub mod find_self_call;
|
||||
|
||||
pub use find_self_call::find_self_call;
|
||||
|
||||
#[derive(Default, Copy, Clone)]
|
||||
pub struct Providers {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! present, and if so we branch off into this module, which implements the attribute by
|
||||
//! implementing a custom lowering from THIR to MIR.
|
||||
//!
|
||||
//! The result of this lowering is returned "normally" from the `build_mir` hook, with the only
|
||||
//! The result of this lowering is returned "normally" from `build_mir`, with the only
|
||||
//! notable difference being that the `injected` field in the body is set. Various components of the
|
||||
//! MIR pipeline, like borrowck and the pass manager will then consult this field (via
|
||||
//! `body.should_skip()`) to skip the parts of the MIR pipeline that precede the MIR phase the user
|
||||
|
|
|
@ -20,7 +20,6 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
|||
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir};
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
|
@ -45,9 +44,9 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Construct the MIR for a given `DefId`.
|
||||
pub(crate) fn build_mir<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> {
|
||||
let tcx = tcx.tcx;
|
||||
/// Create the MIR for a given `DefId`, including unreachable code. Do not call
|
||||
/// this directly; instead use the cached version via `mir_built`.
|
||||
pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
|
||||
tcx.ensure_with_value().thir_abstract_const(def);
|
||||
if let Err(e) = tcx.check_match(def) {
|
||||
return construct_error(tcx, def, e);
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
// The `builder` module used to be named `build`, but that was causing GitHub's
|
||||
// "Go to file" feature to silently ignore all files in the module, probably
|
||||
// because it assumes that "build" is a build-output directory. See #134365.
|
||||
mod builder;
|
||||
pub mod builder;
|
||||
mod check_tail_calls;
|
||||
mod check_unsafety;
|
||||
mod errors;
|
||||
mod thir;
|
||||
pub mod thir;
|
||||
|
||||
use rustc_middle::util::Providers;
|
||||
|
||||
|
@ -27,12 +27,9 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
|||
pub fn provide(providers: &mut Providers) {
|
||||
providers.check_match = thir::pattern::check_match;
|
||||
providers.lit_to_const = thir::constant::lit_to_const;
|
||||
providers.hooks.build_mir = builder::build_mir;
|
||||
providers.closure_saved_names_of_captured_variables =
|
||||
builder::closure_saved_names_of_captured_variables;
|
||||
providers.check_unsafety = check_unsafety::check_unsafety;
|
||||
providers.check_tail_calls = check_tail_calls::check_tail_calls;
|
||||
providers.thir_body = thir::cx::thir_body;
|
||||
providers.hooks.thir_tree = thir::print::thir_tree;
|
||||
providers.hooks.thir_flat = thir::print::thir_flat;
|
||||
}
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
pub(crate) mod constant;
|
||||
pub(crate) mod cx;
|
||||
pub(crate) mod pattern;
|
||||
pub(crate) mod print;
|
||||
pub mod print;
|
||||
mod util;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue