mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Auto merge of #90734 - matthiaskrgr:rollup-e1euotp, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #89561 (Type inference for inline consts) - #90035 (implement rfc-2528 type_changing-struct-update) - #90613 (Allow to run a specific rustdoc-js* test) - #90683 (Make `compiler-docs` only control the default instead of being a hard off-switch) - #90685 (x.py: remove fixme by deleting code) - #90701 (Record more artifact sizes during self-profiling.) - #90723 (Better document `Box` and `alloc::alloc::box_free` connection) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8b09ba6a5d
@ -408,7 +408,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let param = generics.type_param(¶m_ty, tcx);
|
||||
if let Some(generics) = tcx
|
||||
.hir()
|
||||
.get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id()))
|
||||
.get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id()))
|
||||
{
|
||||
suggest_constraining_type_param(
|
||||
tcx,
|
||||
|
@ -376,7 +376,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
let base_def_id = tcx.closure_base_def_id(body.source.def_id());
|
||||
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
|
||||
if !tcx.has_attr(base_def_id, sym::rustc_regions) {
|
||||
return;
|
||||
}
|
||||
|
@ -569,7 +569,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// to store those. Otherwise, we'll pass in `None` to the
|
||||
// functions below, which will trigger them to report errors
|
||||
// eagerly.
|
||||
let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new);
|
||||
let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
|
||||
|
||||
self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
|
||||
|
||||
@ -2229,7 +2229,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
|
||||
tcx,
|
||||
closure_substs,
|
||||
self.num_external_vids,
|
||||
tcx.closure_base_def_id(closure_def_id),
|
||||
tcx.typeck_root_def_id(closure_def_id),
|
||||
);
|
||||
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
|
||||
|
||||
|
@ -10,6 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
@ -1343,13 +1344,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// though.
|
||||
let category = match place.as_local() {
|
||||
Some(RETURN_PLACE) => {
|
||||
if let BorrowCheckContext {
|
||||
universal_regions:
|
||||
UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
|
||||
..
|
||||
} = self.borrowck_context
|
||||
{
|
||||
if tcx.is_static(*def_id) {
|
||||
let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
|
||||
if defining_ty.is_const() {
|
||||
if tcx.is_static(defining_ty.def_id()) {
|
||||
ConstraintCategory::UseAsStatic
|
||||
} else {
|
||||
ConstraintCategory::UseAsConst
|
||||
@ -1527,6 +1524,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
|
||||
self.check_operand(discr, term_location);
|
||||
|
||||
let discr_ty = discr.ty(body, tcx);
|
||||
if let Err(terr) = self.sub_types(
|
||||
discr_ty,
|
||||
@ -1549,6 +1548,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// FIXME: check the values
|
||||
}
|
||||
TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
|
||||
self.check_operand(func, term_location);
|
||||
for arg in args {
|
||||
self.check_operand(arg, term_location);
|
||||
}
|
||||
|
||||
let func_ty = func.ty(body, tcx);
|
||||
debug!("check_terminator: call, func_ty={:?}", func_ty);
|
||||
let sig = match func_ty.kind() {
|
||||
@ -1593,6 +1597,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
|
||||
}
|
||||
TerminatorKind::Assert { ref cond, ref msg, .. } => {
|
||||
self.check_operand(cond, term_location);
|
||||
|
||||
let cond_ty = cond.ty(body, tcx);
|
||||
if cond_ty != tcx.types.bool {
|
||||
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
|
||||
@ -1608,6 +1614,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
TerminatorKind::Yield { ref value, .. } => {
|
||||
self.check_operand(value, term_location);
|
||||
|
||||
let value_ty = value.ty(body, tcx);
|
||||
match body.yield_ty() {
|
||||
None => span_mirbug!(self, term, "yield in non-generator"),
|
||||
@ -1650,7 +1658,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
Some(RETURN_PLACE) => {
|
||||
if let BorrowCheckContext {
|
||||
universal_regions:
|
||||
UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
|
||||
UniversalRegions {
|
||||
defining_ty:
|
||||
DefiningTy::Const(def_id, _)
|
||||
| DefiningTy::InlineConst(def_id, _),
|
||||
..
|
||||
},
|
||||
..
|
||||
} = self.borrowck_context
|
||||
{
|
||||
@ -1931,15 +1944,51 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
|
||||
if let Operand::Constant(constant) = op {
|
||||
let maybe_uneval = match constant.literal {
|
||||
ConstantKind::Ty(ct) => match ct.val {
|
||||
ty::ConstKind::Unevaluated(uv) => Some(uv),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
if let Some(uv) = maybe_uneval {
|
||||
if uv.promoted.is_none() {
|
||||
let tcx = self.tcx();
|
||||
let def_id = uv.def.def_id_for_type_of();
|
||||
if tcx.def_kind(def_id) == DefKind::InlineConst {
|
||||
let predicates = self.prove_closure_bounds(
|
||||
tcx,
|
||||
def_id.expect_local(),
|
||||
uv.substs(tcx),
|
||||
location,
|
||||
);
|
||||
self.normalize_and_prove_instantiated_predicates(
|
||||
def_id,
|
||||
predicates,
|
||||
location.to_locations(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
let tcx = self.tcx();
|
||||
|
||||
match rvalue {
|
||||
Rvalue::Aggregate(ak, ops) => {
|
||||
for op in ops {
|
||||
self.check_operand(op, location);
|
||||
}
|
||||
self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
|
||||
}
|
||||
|
||||
Rvalue::Repeat(operand, len) => {
|
||||
self.check_operand(operand, location);
|
||||
|
||||
// If the length cannot be evaluated we must assume that the length can be larger
|
||||
// than 1.
|
||||
// If the length is larger than 1, the repeat expression will need to copy the
|
||||
@ -1990,7 +2039,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
|
||||
Rvalue::NullaryOp(_, ty) => {
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
|
||||
substs: tcx.mk_substs_trait(ty, &[]),
|
||||
};
|
||||
|
||||
self.prove_trait_ref(
|
||||
trait_ref,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::SizedBound,
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::ShallowInitBox(operand, ty) => {
|
||||
self.check_operand(operand, location);
|
||||
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
|
||||
substs: tcx.mk_substs_trait(ty, &[]),
|
||||
@ -2004,6 +2068,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
|
||||
Rvalue::Cast(cast_kind, op, ty) => {
|
||||
self.check_operand(op, location);
|
||||
|
||||
match cast_kind {
|
||||
CastKind::Pointer(PointerCast::ReifyFnPointer) => {
|
||||
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
|
||||
@ -2250,6 +2316,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
|
||||
box (left, right),
|
||||
) => {
|
||||
self.check_operand(left, location);
|
||||
self.check_operand(right, location);
|
||||
|
||||
let ty_left = left.ty(body, tcx);
|
||||
match ty_left.kind() {
|
||||
// Types with regions are comparable if they have a common super-type.
|
||||
@ -2300,13 +2369,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
|
||||
self.check_operand(operand, location);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_, box (left, right))
|
||||
| Rvalue::CheckedBinaryOp(_, box (left, right)) => {
|
||||
self.check_operand(left, location);
|
||||
self.check_operand(right, location);
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(..)
|
||||
| Rvalue::ThreadLocalRef(..)
|
||||
| Rvalue::Use(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::CheckedBinaryOp(..)
|
||||
| Rvalue::UnaryOp(..)
|
||||
| Rvalue::Discriminant(..) => {}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
|
||||
use std::iter;
|
||||
|
||||
use crate::nll::ToRegionVid;
|
||||
@ -108,6 +108,10 @@ pub enum DefiningTy<'tcx> {
|
||||
/// is that it has no inputs and a single return value, which is
|
||||
/// the value of the constant.
|
||||
Const(DefId, SubstsRef<'tcx>),
|
||||
|
||||
/// The MIR represents an inline const. The signature has no inputs and a
|
||||
/// single return value found via `InlineConstSubsts::ty`.
|
||||
InlineConst(DefId, SubstsRef<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> DefiningTy<'tcx> {
|
||||
@ -121,7 +125,7 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
DefiningTy::Generator(_, substs, _) => {
|
||||
Either::Right(Either::Left(substs.as_generator().upvar_tys()))
|
||||
}
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
|
||||
Either::Right(Either::Right(iter::empty()))
|
||||
}
|
||||
}
|
||||
@ -133,7 +137,7 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
pub fn implicit_inputs(self) -> usize {
|
||||
match self {
|
||||
DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +146,7 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
}
|
||||
|
||||
pub fn is_const(&self) -> bool {
|
||||
matches!(*self, DefiningTy::Const(..))
|
||||
matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
|
||||
}
|
||||
|
||||
pub fn def_id(&self) -> DefId {
|
||||
@ -150,7 +154,8 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
DefiningTy::Closure(def_id, ..)
|
||||
| DefiningTy::Generator(def_id, ..)
|
||||
| DefiningTy::FnDef(def_id, ..)
|
||||
| DefiningTy::Const(def_id, ..) => def_id,
|
||||
| DefiningTy::Const(def_id, ..)
|
||||
| DefiningTy::InlineConst(def_id, ..) => def_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -242,7 +247,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
closure_substs: SubstsRef<'tcx>,
|
||||
expected_num_vars: usize,
|
||||
closure_base_def_id: DefId,
|
||||
typeck_root_def_id: DefId,
|
||||
) -> IndexVec<RegionVid, ty::Region<'tcx>> {
|
||||
let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
|
||||
region_mapping.push(tcx.lifetimes.re_static);
|
||||
@ -250,7 +255,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
region_mapping.push(fr);
|
||||
});
|
||||
|
||||
for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
|
||||
for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
|
||||
region_mapping.push(r);
|
||||
});
|
||||
|
||||
@ -344,8 +349,8 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
// tests, and the resulting print-outs include def-ids
|
||||
// and other things that are not stable across tests!
|
||||
// So we just include the region-vid. Annoying.
|
||||
let closure_base_def_id = tcx.closure_base_def_id(def_id);
|
||||
for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
||||
for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
|
||||
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
|
||||
});
|
||||
}
|
||||
@ -359,8 +364,8 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
// FIXME: As above, we'd like to print out the region
|
||||
// `r` but doing so is not stable across architectures
|
||||
// and so forth.
|
||||
let closure_base_def_id = tcx.closure_base_def_id(def_id);
|
||||
for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
||||
for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
|
||||
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
|
||||
});
|
||||
}
|
||||
@ -376,6 +381,12 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
tcx.def_path_str_with_substs(def_id, substs),
|
||||
));
|
||||
}
|
||||
DefiningTy::InlineConst(def_id, substs) => {
|
||||
err.note(&format!(
|
||||
"defining inline constant type: {}",
|
||||
tcx.def_path_str_with_substs(def_id, substs),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -411,7 +422,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
let mut indices = self.compute_indices(fr_static, defining_ty);
|
||||
debug!("build: indices={:?}", indices);
|
||||
|
||||
let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
|
||||
let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
|
||||
|
||||
// If this is a closure or generator, then the late-bound regions from the enclosing
|
||||
// function are actually external regions to us. For example, here, 'a is not local
|
||||
@ -419,7 +430,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
// fn foo<'a>() {
|
||||
// let c = || { let x: &'a u32 = ...; }
|
||||
// }
|
||||
if self.mir_def.did.to_def_id() != closure_base_def_id {
|
||||
if self.mir_def.did.to_def_id() != typeck_root_def_id {
|
||||
self.infcx
|
||||
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
|
||||
}
|
||||
@ -437,7 +448,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
);
|
||||
// Converse of above, if this is a function then the late-bound regions declared on its
|
||||
// signature are local to the fn.
|
||||
if self.mir_def.did.to_def_id() == closure_base_def_id {
|
||||
if self.mir_def.did.to_def_id() == typeck_root_def_id {
|
||||
self.infcx
|
||||
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
|
||||
}
|
||||
@ -502,12 +513,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
/// see `DefiningTy` for details.
|
||||
fn defining_ty(&self) -> DefiningTy<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
|
||||
|
||||
match tcx.hir().body_owner_kind(self.mir_hir_id) {
|
||||
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
|
||||
let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
|
||||
tcx.type_of(closure_base_def_id)
|
||||
let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
|
||||
tcx.type_of(typeck_root_def_id)
|
||||
} else {
|
||||
let tables = tcx.typeck(self.mir_def.did);
|
||||
tables.node_type(self.mir_hir_id)
|
||||
@ -534,11 +545,21 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
|
||||
assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
|
||||
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
|
||||
let substs =
|
||||
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
|
||||
DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
|
||||
let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
|
||||
if self.mir_def.did.to_def_id() == typeck_root_def_id {
|
||||
let substs =
|
||||
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
|
||||
DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
|
||||
} else {
|
||||
let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
|
||||
let substs = InlineConstSubsts::new(
|
||||
tcx,
|
||||
InlineConstSubstsParts { parent_substs: identity_substs, ty },
|
||||
)
|
||||
.substs;
|
||||
let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
|
||||
DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -553,17 +574,19 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
defining_ty: DefiningTy<'tcx>,
|
||||
) -> UniversalRegionIndices<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
|
||||
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
|
||||
let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
|
||||
let fr_substs = match defining_ty {
|
||||
DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
|
||||
DefiningTy::Closure(_, ref substs)
|
||||
| DefiningTy::Generator(_, ref substs, _)
|
||||
| DefiningTy::InlineConst(_, ref substs) => {
|
||||
// In the case of closures, we rely on the fact that
|
||||
// the first N elements in the ClosureSubsts are
|
||||
// inherited from the `closure_base_def_id`.
|
||||
// inherited from the `typeck_root_def_id`.
|
||||
// Therefore, when we zip together (below) with
|
||||
// `identity_substs`, we will get only those regions
|
||||
// that correspond to early-bound regions declared on
|
||||
// the `closure_base_def_id`.
|
||||
// the `typeck_root_def_id`.
|
||||
assert!(substs.len() >= identity_substs.len());
|
||||
assert_eq!(substs.regions().count(), identity_substs.regions().count());
|
||||
substs
|
||||
@ -648,6 +671,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
let ty = indices.fold_to_region_vids(tcx, ty);
|
||||
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
|
||||
}
|
||||
|
||||
DefiningTy::InlineConst(def_id, substs) => {
|
||||
assert_eq!(self.mir_def.did.to_def_id(), def_id);
|
||||
let ty = substs.as_inline_const().ty();
|
||||
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -736,8 +765,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
) {
|
||||
debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
|
||||
let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
|
||||
for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
|
||||
let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
|
||||
for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
|
||||
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = self.next_nll_region_var(FR);
|
||||
|
@ -17,6 +17,7 @@ use rustc_codegen_ssa::back::write::{
|
||||
};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_errors::{FatalError, Handler, Level};
|
||||
use rustc_fs_util::{link_or_copy, path_to_c_string};
|
||||
@ -53,6 +54,7 @@ pub fn write_output_file(
|
||||
output: &Path,
|
||||
dwo_output: Option<&Path>,
|
||||
file_type: llvm::FileType,
|
||||
self_profiler_ref: &SelfProfilerRef,
|
||||
) -> Result<(), FatalError> {
|
||||
unsafe {
|
||||
let output_c = path_to_c_string(output);
|
||||
@ -76,6 +78,19 @@ pub fn write_output_file(
|
||||
file_type,
|
||||
)
|
||||
};
|
||||
|
||||
// Record artifact sizes for self-profiling
|
||||
if result == llvm::LLVMRustResult::Success {
|
||||
let artifact_kind = match file_type {
|
||||
llvm::FileType::ObjectFile => "object_file",
|
||||
llvm::FileType::AssemblyFile => "assembly_file",
|
||||
};
|
||||
record_artifact_size(self_profiler_ref, artifact_kind, output);
|
||||
if let Some(dwo_file) = dwo_output {
|
||||
record_artifact_size(self_profiler_ref, "dwo_file", dwo_file);
|
||||
}
|
||||
}
|
||||
|
||||
result.into_result().map_err(|()| {
|
||||
let msg = format!("could not write output to {}", output.display());
|
||||
llvm_err(handler, &msg)
|
||||
@ -752,6 +767,14 @@ pub(crate) unsafe fn codegen(
|
||||
let thin = ThinBuffer::new(llmod);
|
||||
let data = thin.data();
|
||||
|
||||
if let Some(bitcode_filename) = bc_out.file_name() {
|
||||
cgcx.prof.artifact_size(
|
||||
"llvm_bitcode",
|
||||
bitcode_filename.to_string_lossy(),
|
||||
data.len() as u64,
|
||||
);
|
||||
}
|
||||
|
||||
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg(
|
||||
"LLVM_module_codegen_emit_bitcode",
|
||||
@ -812,6 +835,11 @@ pub(crate) unsafe fn codegen(
|
||||
}
|
||||
|
||||
let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
|
||||
|
||||
if result == llvm::LLVMRustResult::Success {
|
||||
record_artifact_size(&cgcx.prof, "llvm_ir", &out);
|
||||
}
|
||||
|
||||
result.into_result().map_err(|()| {
|
||||
let msg = format!("failed to write LLVM IR to {}", out.display());
|
||||
llvm_err(diag_handler, &msg)
|
||||
@ -842,6 +870,7 @@ pub(crate) unsafe fn codegen(
|
||||
&path,
|
||||
None,
|
||||
llvm::FileType::AssemblyFile,
|
||||
&cgcx.prof,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
@ -875,6 +904,7 @@ pub(crate) unsafe fn codegen(
|
||||
&obj_out,
|
||||
dwo_out,
|
||||
llvm::FileType::ObjectFile,
|
||||
&cgcx.prof,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
@ -1131,3 +1161,19 @@ fn create_msvc_imps(
|
||||
symbol_name.starts_with(b"__llvm_profile_")
|
||||
}
|
||||
}
|
||||
|
||||
fn record_artifact_size(
|
||||
self_profiler_ref: &SelfProfilerRef,
|
||||
artifact_kind: &'static str,
|
||||
path: &Path,
|
||||
) {
|
||||
// Don't stat the file if we are not going to record its size.
|
||||
if !self_profiler_ref.enabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(artifact_name) = path.file_name() {
|
||||
let file_size = std::fs::metadata(path).map(|m| m.len()).unwrap_or(0);
|
||||
self_profiler_ref.artifact_size(artifact_kind, artifact_name.to_string_lossy(), file_size);
|
||||
}
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
type_names::push_item_name(self.tcx(), def_id, false, &mut name);
|
||||
|
||||
// Find the enclosing function, in case this is a closure.
|
||||
let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
|
||||
let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id);
|
||||
|
||||
// Get_template_parameters() will append a `<...>` clause to the function
|
||||
// name if necessary.
|
||||
|
@ -121,6 +121,19 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
|
||||
if sess.opts.json_artifact_notifications {
|
||||
sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link");
|
||||
}
|
||||
|
||||
if sess.prof.enabled() {
|
||||
if let Some(artifact_name) = out_filename.file_name() {
|
||||
// Record size for self-profiling
|
||||
let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
|
||||
|
||||
sess.prof.artifact_size(
|
||||
"linked_artifact",
|
||||
artifact_name.to_string_lossy(),
|
||||
file_size,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|
||||
| DefKind::Static
|
||||
| DefKind::ConstParam
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::AssocConst
|
||||
),
|
||||
"Unexpected DefKind: {:?}",
|
||||
|
@ -104,8 +104,10 @@ pub enum DefKind {
|
||||
Use,
|
||||
/// An `extern` block.
|
||||
ForeignMod,
|
||||
/// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`, or `const { 1 + 2}`
|
||||
/// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`
|
||||
AnonConst,
|
||||
/// An inline constant, e.g. `const { 1 + 2 }`
|
||||
InlineConst,
|
||||
/// Opaque type, aka `impl Trait`.
|
||||
OpaqueTy,
|
||||
Field,
|
||||
@ -155,6 +157,7 @@ impl DefKind {
|
||||
DefKind::Use => "import",
|
||||
DefKind::ForeignMod => "foreign module",
|
||||
DefKind::AnonConst => "constant expression",
|
||||
DefKind::InlineConst => "inline constant",
|
||||
DefKind::Field => "field",
|
||||
DefKind::Impl => "implementation",
|
||||
DefKind::Closure => "closure",
|
||||
@ -174,6 +177,7 @@ impl DefKind {
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Impl
|
||||
| DefKind::Use
|
||||
| DefKind::InlineConst
|
||||
| DefKind::ExternCrate => "an",
|
||||
DefKind::Macro(macro_kind) => macro_kind.article(),
|
||||
_ => "a",
|
||||
@ -207,6 +211,7 @@ impl DefKind {
|
||||
|
||||
// Not namespaced.
|
||||
DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::Field
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::ExternCrate
|
||||
|
@ -99,7 +99,7 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
|
||||
/// function. We can then add implied bounds and the like from the
|
||||
/// closure arguments into the environment -- these should only
|
||||
/// apply in the closure body, so once we exit, we invoke
|
||||
/// `pop_snapshot_post_closure` to remove them.
|
||||
/// `pop_snapshot_post_typeck_child` to remove them.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
@ -129,12 +129,12 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
|
||||
/// seems like it'd be readily fixed if we wanted. There are
|
||||
/// similar leaks around givens that seem equally suspicious, to
|
||||
/// be honest. --nmatsakis
|
||||
pub fn push_snapshot_pre_closure(&self) -> usize {
|
||||
pub fn push_snapshot_pre_typeck_child(&self) -> usize {
|
||||
self.region_bound_pairs_accum.len()
|
||||
}
|
||||
|
||||
/// See `push_snapshot_pre_closure`.
|
||||
pub fn pop_snapshot_post_closure(&mut self, len: usize) {
|
||||
/// See `push_snapshot_pre_typeck_child`.
|
||||
pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) {
|
||||
self.region_bound_pairs_accum.truncate(len);
|
||||
}
|
||||
|
||||
|
@ -797,6 +797,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
|
||||
| DefKind::ConstParam
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Closure
|
||||
| DefKind::Generator
|
||||
@ -832,6 +833,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
|
||||
DefKind::Use
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Closure
|
||||
| DefKind::Generator
|
||||
@ -856,9 +858,11 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
|
||||
(true, mir_opt_base)
|
||||
}
|
||||
// Constants
|
||||
DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => {
|
||||
(true, false)
|
||||
}
|
||||
DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Static
|
||||
| DefKind::Const => (true, false),
|
||||
// Full-fledged functions
|
||||
DefKind::AssocFn | DefKind::Fn => {
|
||||
let generics = tcx.generics_of(def_id);
|
||||
@ -914,6 +918,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
|
||||
| DefKind::Use
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Closure
|
||||
| DefKind::Generator
|
||||
@ -939,6 +944,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Impl
|
||||
| DefKind::Field
|
||||
@ -2187,5 +2193,8 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
|
||||
result[header + 2] = (pos >> 8) as u8;
|
||||
result[header + 3] = (pos >> 0) as u8;
|
||||
|
||||
// Record metadata size for self-profiling
|
||||
tcx.prof.artifact_size("crate_metadata", "crate_metadata", result.len() as u64);
|
||||
|
||||
EncodedMetadata { raw_data: result }
|
||||
}
|
||||
|
@ -266,7 +266,15 @@ impl<'hir> Map<'hir> {
|
||||
};
|
||||
DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data))
|
||||
}
|
||||
Node::AnonConst(_) => DefKind::AnonConst,
|
||||
Node::AnonConst(_) => {
|
||||
let inline = match self.find(self.get_parent_node(hir_id)) {
|
||||
Some(Node::Expr(&Expr {
|
||||
kind: ExprKind::ConstBlock(ref anon_const), ..
|
||||
})) if anon_const.hir_id == hir_id => true,
|
||||
_ => false,
|
||||
};
|
||||
if inline { DefKind::InlineConst } else { DefKind::AnonConst }
|
||||
}
|
||||
Node::Field(_) => DefKind::Field,
|
||||
Node::Expr(expr) => match expr.kind {
|
||||
ExprKind::Closure(.., None) => DefKind::Closure,
|
||||
|
@ -958,7 +958,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Res
|
||||
write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })?
|
||||
}
|
||||
(_, _) if is_function => write!(w, "fn ")?,
|
||||
(DefKind::AnonConst, _) => {} // things like anon const, not an item
|
||||
(DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
|
||||
_ => bug!("Unexpected def kind {:?}", kind),
|
||||
}
|
||||
|
||||
|
@ -797,7 +797,7 @@ rustc_queries! {
|
||||
/// additional requirements that the closure's creator must verify.
|
||||
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
|
||||
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
|
||||
cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) }
|
||||
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
|
||||
}
|
||||
query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
|
||||
desc {
|
||||
|
@ -1,7 +1,9 @@
|
||||
use crate::mir::interpret::ConstValue;
|
||||
use crate::mir::interpret::{LitToConstInput, Scalar};
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::ty::{ParamEnv, ParamEnvAnd};
|
||||
use crate::ty::{
|
||||
self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
|
||||
TyCtxt, TypeFoldable,
|
||||
};
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
@ -54,6 +56,24 @@ impl<'tcx> Const<'tcx> {
|
||||
|
||||
let ty = tcx.type_of(def.def_id_for_type_of());
|
||||
|
||||
match Self::try_eval_lit_or_param(tcx, ty, expr) {
|
||||
Some(v) => v,
|
||||
None => tcx.mk_const(ty::Const {
|
||||
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
|
||||
def: def.to_global(),
|
||||
substs_: None,
|
||||
promoted: None,
|
||||
}),
|
||||
ty,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_eval_lit_or_param(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> Option<&'tcx Self> {
|
||||
let lit_input = match expr.kind {
|
||||
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
|
||||
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
|
||||
@ -69,7 +89,7 @@ impl<'tcx> Const<'tcx> {
|
||||
// If an error occurred, ignore that it's a literal and leave reporting the error up to
|
||||
// mir.
|
||||
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
|
||||
return c;
|
||||
return Some(c);
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
|
||||
}
|
||||
@ -85,7 +105,7 @@ impl<'tcx> Const<'tcx> {
|
||||
};
|
||||
|
||||
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
|
||||
let val = match expr.kind {
|
||||
match expr.kind {
|
||||
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
|
||||
// Find the name and index of the const parameter by indexing the generics of
|
||||
// the parent item and construct a `ParamConst`.
|
||||
@ -95,16 +115,53 @@ impl<'tcx> Const<'tcx> {
|
||||
let generics = tcx.generics_of(item_def_id.to_def_id());
|
||||
let index = generics.param_def_id_to_index[&def_id];
|
||||
let name = tcx.hir().name(hir_id);
|
||||
ty::ConstKind::Param(ty::ParamConst::new(index, name))
|
||||
Some(tcx.mk_const(ty::Const {
|
||||
val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
|
||||
ty,
|
||||
}))
|
||||
}
|
||||
_ => ty::ConstKind::Unevaluated(ty::Unevaluated {
|
||||
def: def.to_global(),
|
||||
substs_: None,
|
||||
promoted: None,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
|
||||
debug!("Const::from_inline_const(def_id={:?})", def_id);
|
||||
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
|
||||
let body_id = match tcx.hir().get(hir_id) {
|
||||
hir::Node::AnonConst(ac) => ac.body,
|
||||
_ => span_bug!(
|
||||
tcx.def_span(def_id.to_def_id()),
|
||||
"from_inline_const can only process anonymous constants"
|
||||
),
|
||||
};
|
||||
|
||||
tcx.mk_const(ty::Const { val, ty })
|
||||
let expr = &tcx.hir().body(body_id).value;
|
||||
|
||||
let ty = tcx.typeck(def_id).node_type(hir_id);
|
||||
|
||||
let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
|
||||
let parent_substs =
|
||||
tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
|
||||
let substs =
|
||||
InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
|
||||
.substs;
|
||||
tcx.mk_const(ty::Const {
|
||||
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
|
||||
def: ty::WithOptConstParam::unknown(def_id).to_global(),
|
||||
substs_: Some(substs),
|
||||
promoted: None,
|
||||
}),
|
||||
ty,
|
||||
})
|
||||
}
|
||||
};
|
||||
debug_assert!(!ret.has_free_regions(tcx));
|
||||
ret
|
||||
}
|
||||
|
||||
/// Interns the given value as a constant.
|
||||
|
@ -42,6 +42,7 @@ pub enum TypeError<'tcx> {
|
||||
TupleSize(ExpectedFound<usize>),
|
||||
FixedArraySize(ExpectedFound<u64>),
|
||||
ArgCount,
|
||||
FieldMisMatch(Symbol, Symbol),
|
||||
|
||||
RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
|
||||
RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>),
|
||||
@ -134,6 +135,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
||||
pluralize!(values.found)
|
||||
),
|
||||
ArgCount => write!(f, "incorrect number of function parameters"),
|
||||
FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field),
|
||||
RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"),
|
||||
RegionsInsufficientlyPolymorphic(br, _) => write!(
|
||||
f,
|
||||
@ -224,6 +226,7 @@ impl<'tcx> TypeError<'tcx> {
|
||||
| ArgumentMutability(_)
|
||||
| TupleSize(_)
|
||||
| ArgCount
|
||||
| FieldMisMatch(..)
|
||||
| RegionsDoesNotOutlive(..)
|
||||
| RegionsInsufficientlyPolymorphic(..)
|
||||
| RegionsOverlyPolymorphic(..)
|
||||
|
@ -74,9 +74,10 @@ pub use self::sty::{
|
||||
Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
|
||||
CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion,
|
||||
ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
|
||||
GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
|
||||
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
|
||||
RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
|
||||
GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
|
||||
ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
|
||||
PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
|
||||
UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
|
||||
};
|
||||
pub use self::trait_def::TraitDef;
|
||||
|
||||
@ -1927,7 +1928,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
| DefKind::Static
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
|
||||
// If the caller wants `mir_for_ctfe` of a function they should not be using
|
||||
// `instance_mir`, so we'll assume const fn also wants the optimized version.
|
||||
_ => {
|
||||
|
@ -602,6 +602,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
|
||||
TupleSize(x) => TupleSize(x),
|
||||
FixedArraySize(x) => FixedArraySize(x),
|
||||
ArgCount => ArgCount,
|
||||
FieldMisMatch(x, y) => FieldMisMatch(x, y),
|
||||
RegionsDoesNotOutlive(a, b) => {
|
||||
return tcx.lift((a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b));
|
||||
}
|
||||
|
@ -704,6 +704,66 @@ impl<'tcx> UpvarSubsts<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An inline const is modeled like
|
||||
///
|
||||
/// const InlineConst<'l0...'li, T0...Tj, R>: R;
|
||||
///
|
||||
/// where:
|
||||
///
|
||||
/// - 'l0...'li and T0...Tj are the generic parameters
|
||||
/// inherited from the item that defined the inline const,
|
||||
/// - R represents the type of the constant.
|
||||
///
|
||||
/// When the inline const is instantiated, `R` is substituted as the actual inferred
|
||||
/// type of the constant. The reason that `R` is represented as an extra type parameter
|
||||
/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
|
||||
/// inline const can reference lifetimes that are internal to the creating function.
|
||||
#[derive(Copy, Clone, Debug, TypeFoldable)]
|
||||
pub struct InlineConstSubsts<'tcx> {
|
||||
/// Generic parameters from the enclosing item,
|
||||
/// concatenated with the inferred type of the constant.
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
}
|
||||
|
||||
/// Struct returned by `split()`.
|
||||
pub struct InlineConstSubstsParts<'tcx, T> {
|
||||
pub parent_substs: &'tcx [GenericArg<'tcx>],
|
||||
pub ty: T,
|
||||
}
|
||||
|
||||
impl<'tcx> InlineConstSubsts<'tcx> {
|
||||
/// Construct `InlineConstSubsts` from `InlineConstSubstsParts`.
|
||||
pub fn new(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>,
|
||||
) -> InlineConstSubsts<'tcx> {
|
||||
InlineConstSubsts {
|
||||
substs: tcx.mk_substs(
|
||||
parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Divides the inline const substs into their respective components.
|
||||
/// The ordering assumed here must match that used by `InlineConstSubsts::new` above.
|
||||
fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> {
|
||||
match self.substs[..] {
|
||||
[ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty },
|
||||
_ => bug!("inline const substs missing synthetics"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the substitutions of the inline const's parent.
|
||||
pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
|
||||
self.split().parent_substs
|
||||
}
|
||||
|
||||
/// Returns the type of this inline const.
|
||||
pub fn ty(self) -> Ty<'tcx> {
|
||||
self.split().ty.expect_ty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable)]
|
||||
pub enum ExistentialPredicate<'tcx> {
|
||||
|
@ -3,7 +3,7 @@
|
||||
use crate::mir;
|
||||
use crate::ty::codec::{TyDecoder, TyEncoder};
|
||||
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
|
||||
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
|
||||
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -204,6 +204,14 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
|
||||
GeneratorSubsts { substs: self }
|
||||
}
|
||||
|
||||
/// Interpret these substitutions as the substitutions of an inline const.
|
||||
/// Inline const substitutions have a particular structure controlled by the
|
||||
/// compiler that encodes information like the inferred type;
|
||||
/// see `ty::InlineConstSubsts` struct for more comments.
|
||||
pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> {
|
||||
InlineConstSubsts { substs: self }
|
||||
}
|
||||
|
||||
/// Creates an `InternalSubsts` that maps each generic parameter to itself.
|
||||
pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
|
||||
Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))
|
||||
|
@ -423,6 +423,15 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator)
|
||||
}
|
||||
|
||||
/// Returns `true` if `def_id` refers to a definition that does not have its own
|
||||
/// type-checking context, i.e. closure, generator or inline const.
|
||||
pub fn is_typeck_child(self, def_id: DefId) -> bool {
|
||||
matches!(
|
||||
self.def_kind(def_id),
|
||||
DefKind::Closure | DefKind::Generator | DefKind::InlineConst
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
|
||||
pub fn is_trait(self, def_id: DefId) -> bool {
|
||||
self.def_kind(def_id) == DefKind::Trait
|
||||
@ -440,16 +449,19 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
matches!(self.def_kind(def_id), DefKind::Ctor(..))
|
||||
}
|
||||
|
||||
/// Given the def-ID of a fn or closure, returns the def-ID of
|
||||
/// the innermost fn item that the closure is contained within.
|
||||
/// This is a significant `DefId` because, when we do
|
||||
/// type-checking, we type-check this fn item and all of its
|
||||
/// (transitive) closures together. Therefore, when we fetch the
|
||||
/// Given the `DefId`, returns the `DefId` of the innermost item that
|
||||
/// has its own type-checking context or "inference enviornment".
|
||||
///
|
||||
/// For example, a closure has its own `DefId`, but it is type-checked
|
||||
/// with the containing item. Similarly, an inline const block has its
|
||||
/// own `DefId` but it is type-checked together with the containing item.
|
||||
///
|
||||
/// Therefore, when we fetch the
|
||||
/// `typeck` the closure, for example, we really wind up
|
||||
/// fetching the `typeck` the enclosing fn item.
|
||||
pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
|
||||
pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
|
||||
let mut def_id = def_id;
|
||||
while self.is_closure(def_id) {
|
||||
while self.is_typeck_child(def_id) {
|
||||
def_id = self.parent(def_id).unwrap_or_else(|| {
|
||||
bug!("closure {:?} has no parent", def_id);
|
||||
});
|
||||
|
@ -578,7 +578,7 @@ impl<'tcx> Cx<'tcx> {
|
||||
|
||||
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
|
||||
let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
|
||||
let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
|
||||
|
||||
ExprKind::ConstBlock { value }
|
||||
}
|
||||
|
@ -544,7 +544,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
let (lit, neg) = match expr.kind {
|
||||
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
|
||||
let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
|
||||
let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
|
||||
if matches!(value.val, ConstKind::Param(_)) {
|
||||
let span = self.tcx.hir().span(anon_const.hir_id);
|
||||
self.errors.push(PatternError::ConstParamInPattern(span));
|
||||
|
@ -361,6 +361,17 @@ fn collect_and_partition_mono_items<'tcx>(
|
||||
)
|
||||
});
|
||||
|
||||
if tcx.prof.enabled() {
|
||||
// Record CGU size estimates for self-profiling.
|
||||
for cgu in codegen_units {
|
||||
tcx.prof.artifact_size(
|
||||
"codegen_unit_size_estimate",
|
||||
&cgu.name().as_str()[..],
|
||||
cgu.size_estimate() as u64,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mono_items: DefIdSet = items
|
||||
.iter()
|
||||
.filter_map(|mono_item| match *mono_item {
|
||||
|
@ -167,6 +167,7 @@ fn mark_used_by_default_parameters<'tcx>(
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Field
|
||||
| DefKind::LifetimeParam
|
||||
@ -195,7 +196,7 @@ fn emit_unused_generic_params_error<'tcx>(
|
||||
generics: &'tcx ty::Generics,
|
||||
unused_parameters: &FiniteBitSet<u32>,
|
||||
) {
|
||||
let base_def_id = tcx.closure_base_def_id(def_id);
|
||||
let base_def_id = tcx.typeck_root_def_id(def_id);
|
||||
if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
|
||||
return;
|
||||
}
|
||||
@ -303,7 +304,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
ty::ConstKind::Unevaluated(uv)
|
||||
if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
|
||||
if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) =>
|
||||
{
|
||||
self.visit_child_body(uv.def.did, uv.substs(self.tcx));
|
||||
ControlFlow::CONTINUE
|
||||
|
@ -334,9 +334,10 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
||||
// properly, we can't miss any types.
|
||||
|
||||
match expr.kind {
|
||||
// Manually recurse over closures, because they are the only
|
||||
// Manually recurse over closures and inline consts, because they are the only
|
||||
// case of nested bodies that share the parent environment.
|
||||
hir::ExprKind::Closure(.., body, _, _) => {
|
||||
hir::ExprKind::Closure(.., body, _, _)
|
||||
| hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
|
||||
let body = visitor.tcx.hir().body(body);
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
@ -817,9 +818,9 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
||||
}
|
||||
|
||||
fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
|
||||
let closure_base_def_id = tcx.closure_base_def_id(def_id);
|
||||
if closure_base_def_id != def_id {
|
||||
return tcx.region_scope_tree(closure_base_def_id);
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
||||
if typeck_root_def_id != def_id {
|
||||
return tcx.region_scope_tree(typeck_root_def_id);
|
||||
}
|
||||
|
||||
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||
|
@ -618,6 +618,7 @@ impl EmbargoVisitor<'tcx> {
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::Field
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Impl
|
||||
|
@ -967,6 +967,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::Field
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::GlobalAsm
|
||||
|
@ -540,7 +540,7 @@ fn is_late_bound_map<'tcx>(
|
||||
def_id: LocalDefId,
|
||||
) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::AnonConst => {
|
||||
DefKind::AnonConst | DefKind::InlineConst => {
|
||||
let mut def_id = tcx
|
||||
.parent(def_id.to_def_id())
|
||||
.unwrap_or_else(|| bug!("anon const or closure without a parent"));
|
||||
|
@ -739,6 +739,7 @@ impl<'tcx> SaveContext<'tcx> {
|
||||
| HirDefKind::ForeignMod
|
||||
| HirDefKind::LifetimeParam
|
||||
| HirDefKind::AnonConst
|
||||
| HirDefKind::InlineConst
|
||||
| HirDefKind::Use
|
||||
| HirDefKind::Field
|
||||
| HirDefKind::GlobalAsm
|
||||
|
@ -151,7 +151,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
||||
|
||||
if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
|
||||
match infcx.tcx.def_kind(uv.def.did) {
|
||||
DefKind::AnonConst => {
|
||||
DefKind::AnonConst | DefKind::InlineConst => {
|
||||
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
|
||||
|
||||
if mir_body.is_polymorphic {
|
||||
@ -495,7 +495,7 @@ pub(super) fn thir_abstract_const<'tcx>(
|
||||
// we want to look into them or treat them as opaque projections.
|
||||
//
|
||||
// Right now we do neither of that and simply always fail to unify them.
|
||||
DefKind::AnonConst => (),
|
||||
DefKind::AnonConst | DefKind::InlineConst => (),
|
||||
_ => return Ok(None),
|
||||
}
|
||||
|
||||
|
@ -1474,7 +1474,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
let span = self.tcx.def_span(generator_did);
|
||||
|
||||
let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
|
||||
let generator_did_root = self.tcx.closure_base_def_id(generator_did);
|
||||
let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
|
||||
debug!(
|
||||
"maybe_note_obligation_cause_for_async_await: generator_did={:?} \
|
||||
generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}",
|
||||
|
@ -92,7 +92,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
let parent_substs = InternalSubsts::identity_for_item(
|
||||
self.tcx,
|
||||
self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
|
||||
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
|
||||
);
|
||||
|
||||
let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
|
||||
|
@ -30,15 +30,20 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder,
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{ExprKind, QPath};
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
|
||||
use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
|
||||
use rustc_middle::ty::relate::expected_found_bool;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::TypeFoldable;
|
||||
use rustc_middle::ty::{AdtKind, Visibility};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::edition::LATEST_STABLE_EDITION;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::lev_distance::find_best_match_for_name;
|
||||
@ -323,7 +328,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
|
||||
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
|
||||
ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
|
||||
ExprKind::ConstBlock(ref anon_const) => {
|
||||
self.check_expr_const_block(anon_const, expected, expr)
|
||||
}
|
||||
ExprKind::Repeat(element, ref count) => {
|
||||
self.check_expr_repeat(element, count, expected, expr)
|
||||
}
|
||||
@ -1166,6 +1173,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.tcx.mk_array(element_ty, args.len() as u64)
|
||||
}
|
||||
|
||||
fn check_expr_const_block(
|
||||
&self,
|
||||
anon_const: &'tcx hir::AnonConst,
|
||||
expected: Expectation<'tcx>,
|
||||
_expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let body = self.tcx.hir().body(anon_const.body);
|
||||
|
||||
// Create a new function context.
|
||||
let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id);
|
||||
crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
|
||||
|
||||
let ty = fcx.check_expr_with_expectation(&body.value, expected);
|
||||
fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
|
||||
fcx.write_ty(anon_const.hir_id, ty);
|
||||
ty
|
||||
}
|
||||
|
||||
fn check_expr_repeat(
|
||||
&self,
|
||||
element: &'tcx hir::Expr<'tcx>,
|
||||
@ -1262,49 +1287,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
.emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() });
|
||||
}
|
||||
|
||||
let error_happened = self.check_expr_struct_fields(
|
||||
self.check_expr_struct_fields(
|
||||
adt_ty,
|
||||
expected,
|
||||
expr.hir_id,
|
||||
qpath.span(),
|
||||
variant,
|
||||
fields,
|
||||
base_expr.is_none(),
|
||||
base_expr,
|
||||
expr.span,
|
||||
);
|
||||
if let Some(base_expr) = base_expr {
|
||||
// If check_expr_struct_fields hit an error, do not attempt to populate
|
||||
// the fields with the base_expr. This could cause us to hit errors later
|
||||
// when certain fields are assumed to exist that in fact do not.
|
||||
if !error_happened {
|
||||
self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {});
|
||||
match adt_ty.kind() {
|
||||
ty::Adt(adt, substs) if adt.is_struct() => {
|
||||
let fru_field_types = adt
|
||||
.non_enum_variant()
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| {
|
||||
self.normalize_associated_types_in(
|
||||
expr.span,
|
||||
f.ty(self.tcx, substs),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.fru_field_types_mut()
|
||||
.insert(expr.hir_id, fru_field_types);
|
||||
}
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized);
|
||||
adt_ty
|
||||
}
|
||||
@ -1317,9 +1310,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span: Span,
|
||||
variant: &'tcx ty::VariantDef,
|
||||
ast_fields: &'tcx [hir::ExprField<'tcx>],
|
||||
check_completeness: bool,
|
||||
base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
|
||||
expr_span: Span,
|
||||
) -> bool {
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
|
||||
let adt_ty_hint = self
|
||||
@ -1394,7 +1387,116 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
} else if check_completeness && !error_happened && !remaining_fields.is_empty() {
|
||||
}
|
||||
|
||||
// If check_expr_struct_fields hit an error, do not attempt to populate
|
||||
// the fields with the base_expr. This could cause us to hit errors later
|
||||
// when certain fields are assumed to exist that in fact do not.
|
||||
if error_happened {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(base_expr) = base_expr {
|
||||
// FIXME: We are currently creating two branches here in order to maintain
|
||||
// consistency. But they should be merged as much as possible.
|
||||
let fru_tys = if self.tcx.features().type_changing_struct_update {
|
||||
let base_ty = self.check_expr(base_expr);
|
||||
match adt_ty.kind() {
|
||||
ty::Adt(adt, substs) if adt.is_struct() => {
|
||||
match base_ty.kind() {
|
||||
ty::Adt(base_adt, base_subs) if adt == base_adt => {
|
||||
variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| {
|
||||
let fru_ty = self.normalize_associated_types_in(
|
||||
expr_span,
|
||||
self.field_ty(base_expr.span, f, base_subs),
|
||||
);
|
||||
let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
|
||||
if let Some(_) = remaining_fields.remove(&ident) {
|
||||
let target_ty =
|
||||
self.field_ty(base_expr.span, f, substs);
|
||||
let cause = self.misc(base_expr.span);
|
||||
match self
|
||||
.at(&cause, self.param_env)
|
||||
.sup(target_ty, fru_ty)
|
||||
{
|
||||
Ok(InferOk { obligations, value: () }) => {
|
||||
self.register_predicates(obligations)
|
||||
}
|
||||
// FIXME: Need better diagnostics for `FieldMisMatch` error
|
||||
Err(_) => self
|
||||
.report_mismatched_types(
|
||||
&cause,
|
||||
target_ty,
|
||||
fru_ty,
|
||||
FieldMisMatch(
|
||||
variant.ident.name,
|
||||
ident.name,
|
||||
),
|
||||
)
|
||||
.emit(),
|
||||
}
|
||||
}
|
||||
fru_ty
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
_ => {
|
||||
return self
|
||||
.report_mismatched_types(
|
||||
&self.misc(base_expr.span),
|
||||
adt_ty,
|
||||
base_ty,
|
||||
Sorts(expected_found_bool(true, adt_ty, base_ty)),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return self
|
||||
.tcx
|
||||
.sess
|
||||
.emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
|
||||
let base_ty = self.check_expr(base_expr);
|
||||
let same_adt = match (adt_ty.kind(), base_ty.kind()) {
|
||||
(ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true,
|
||||
_ => false,
|
||||
};
|
||||
if self.tcx.sess.is_nightly_build() && same_adt {
|
||||
feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::type_changing_struct_update,
|
||||
base_expr.span,
|
||||
"type changing struct updating is experimental",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
});
|
||||
match adt_ty.kind() {
|
||||
ty::Adt(adt, substs) if adt.is_struct() => variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| {
|
||||
self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs))
|
||||
})
|
||||
.collect(),
|
||||
_ => {
|
||||
return self
|
||||
.tcx
|
||||
.sess
|
||||
.emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
|
||||
}
|
||||
}
|
||||
};
|
||||
self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
|
||||
} else if kind_name != "union" && !remaining_fields.is_empty() {
|
||||
let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
|
||||
!field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
|
||||
});
|
||||
@ -1405,8 +1507,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.report_missing_fields(adt_ty, span, remaining_fields);
|
||||
}
|
||||
}
|
||||
|
||||
error_happened
|
||||
}
|
||||
|
||||
fn check_struct_fields_on_error(
|
||||
|
@ -297,9 +297,9 @@ fn primary_body_of(
|
||||
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
// Closures' typeck results come from their outermost function,
|
||||
// as they are part of the same "inference environment".
|
||||
let outer_def_id = tcx.closure_base_def_id(def_id);
|
||||
if outer_def_id != def_id {
|
||||
return tcx.has_typeck_results(outer_def_id);
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
||||
if typeck_root_def_id != def_id {
|
||||
return tcx.has_typeck_results(typeck_root_def_id);
|
||||
}
|
||||
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
@ -348,9 +348,9 @@ fn typeck_with_fallback<'tcx>(
|
||||
) -> &'tcx ty::TypeckResults<'tcx> {
|
||||
// Closures' typeck results come from their outermost function,
|
||||
// as they are part of the same "inference environment".
|
||||
let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
|
||||
if outer_def_id != def_id {
|
||||
return tcx.typeck(outer_def_id);
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
|
||||
if typeck_root_def_id != def_id {
|
||||
return tcx.typeck(typeck_root_def_id);
|
||||
}
|
||||
|
||||
let id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
|
@ -292,7 +292,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
|
||||
// All other literals result in non-reference types.
|
||||
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`.
|
||||
PatKind::Lit(lt) => match self.check_expr(lt).kind() {
|
||||
//
|
||||
// Call `resolve_vars_if_possible` here for inline const blocks.
|
||||
PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() {
|
||||
ty::Ref(..) => AdjustMode::Pass,
|
||||
_ => AdjustMode::Peel,
|
||||
},
|
||||
|
@ -341,6 +341,29 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
|
||||
self.visit_region_obligations(body_id.hir_id);
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
|
||||
debug!("visit_inline_const(id={:?})", id);
|
||||
|
||||
// Save state of current function. We will restore afterwards.
|
||||
let old_body_id = self.body_id;
|
||||
let old_body_owner = self.body_owner;
|
||||
let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
|
||||
|
||||
let body_id = body.id();
|
||||
self.body_id = body_id.hir_id;
|
||||
self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
|
||||
|
||||
self.outlives_environment.save_implied_bounds(body_id.hir_id);
|
||||
|
||||
self.visit_body(body);
|
||||
self.visit_region_obligations(body_id.hir_id);
|
||||
|
||||
// Restore state from previous function.
|
||||
self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
|
||||
self.body_id = old_body_id;
|
||||
self.body_owner = old_body_owner;
|
||||
}
|
||||
|
||||
fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
|
||||
debug!("visit_region_obligations: hir_id={:?}", hir_id);
|
||||
|
||||
@ -406,13 +429,13 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
|
||||
// `visit_fn_body`. We will restore afterwards.
|
||||
let old_body_id = self.body_id;
|
||||
let old_body_owner = self.body_owner;
|
||||
let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
|
||||
let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
|
||||
|
||||
let body = self.tcx.hir().body(body_id);
|
||||
self.visit_fn_body(hir_id, body, span);
|
||||
|
||||
// Restore state from previous function.
|
||||
self.outlives_environment.pop_snapshot_post_closure(env_snapshot);
|
||||
self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
|
||||
self.body_id = old_body_id;
|
||||
self.body_owner = old_body_owner;
|
||||
}
|
||||
@ -460,6 +483,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
hir::ExprKind::ConstBlock(anon_const) => {
|
||||
let body = self.tcx.hir().body(anon_const.body);
|
||||
self.visit_inline_const(anon_const.hir_id, body);
|
||||
}
|
||||
|
||||
_ => intravisit::walk_expr(self, expr),
|
||||
}
|
||||
}
|
||||
|
@ -148,10 +148,17 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind {
|
||||
let body = self.fcx.tcx.hir().body(body_id);
|
||||
self.visit_body(body);
|
||||
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
|
||||
match expr.kind {
|
||||
hir::ExprKind::Closure(cc, _, body_id, _, _) => {
|
||||
let body = self.fcx.tcx.hir().body(body_id);
|
||||
self.visit_body(body);
|
||||
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(anon_const) => {
|
||||
let body = self.fcx.tcx.hir().body(anon_const.body);
|
||||
self.visit_body(body);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
|
@ -282,6 +282,12 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||
hir::ExprKind::Field(..) => {
|
||||
self.visit_field_id(e.hir_id);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(anon_const) => {
|
||||
self.visit_node_id(e.span, anon_const.hir_id);
|
||||
|
||||
let body = self.tcx().hir().body(anon_const.body);
|
||||
self.visit_body(body);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -1494,13 +1494,15 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
{
|
||||
Some(parent_def_id.to_def_id())
|
||||
}
|
||||
|
||||
Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
|
||||
Some(tcx.typeck_root_def_id(def_id))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
|
||||
Some(tcx.closure_base_def_id(def_id))
|
||||
Some(tcx.typeck_root_def_id(def_id))
|
||||
}
|
||||
Node::Item(item) => match item.kind {
|
||||
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
|
||||
@ -1692,6 +1694,24 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
}));
|
||||
}
|
||||
|
||||
// provide junk type parameter defs for const blocks.
|
||||
if let Node::AnonConst(_) = node {
|
||||
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
|
||||
if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
|
||||
params.push(ty::GenericParamDef {
|
||||
index: type_start,
|
||||
name: Symbol::intern("<const_ty>"),
|
||||
def_id,
|
||||
pure_wrt_drop: false,
|
||||
kind: ty::GenericParamDefKind::Type {
|
||||
has_default: false,
|
||||
object_lifetime_default: rl::Set1::Empty,
|
||||
synthetic: None,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
|
||||
|
||||
ty::Generics {
|
||||
|
@ -494,7 +494,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
||||
Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
|
||||
if anon_const.hir_id == hir_id =>
|
||||
{
|
||||
tcx.typeck(def_id).node_type(anon_const.hir_id)
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
|
||||
substs.as_inline_const().ty()
|
||||
}
|
||||
|
||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||
|
@ -169,6 +169,9 @@ use crate::vec::Vec;
|
||||
#[lang = "owned_box"]
|
||||
#[fundamental]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// The declaration of the `Box` struct must be kept in sync with the
|
||||
// `alloc::alloc::box_free` function or ICEs will happen. See the comment
|
||||
// on `box_free` for more details.
|
||||
pub struct Box<
|
||||
T: ?Sized,
|
||||
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
|
||||
|
@ -96,7 +96,8 @@ impl Step for RustcDocs {
|
||||
const DEFAULT: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/librustc")
|
||||
let builder = run.builder;
|
||||
run.path("rustc-docs").default_condition(builder.config.compiler_docs)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
@ -106,9 +107,6 @@ impl Step for RustcDocs {
|
||||
/// Builds the `rustc-docs` installer component.
|
||||
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
|
||||
let host = self.host;
|
||||
if !builder.config.compiler_docs {
|
||||
return None;
|
||||
}
|
||||
builder.default_doc(&[]);
|
||||
|
||||
let mut tarball = Tarball::new(builder, "rustc-docs", &host.triple);
|
||||
|
@ -529,7 +529,7 @@ impl Step for Rustc {
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
let builder = run.builder;
|
||||
run.krate("rustc-main").path("compiler").default_condition(builder.config.docs)
|
||||
run.krate("rustc-main").path("compiler").default_condition(builder.config.compiler_docs)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
@ -560,11 +560,6 @@ impl Step for Rustc {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
|
||||
builder.info("\tskipping - compiler/librustdoc docs disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the intended out directory for compiler documentation.
|
||||
let out = builder.compiler_doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
@ -674,7 +669,8 @@ macro_rules! tool_doc {
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.krate($should_run)
|
||||
let builder = run.builder;
|
||||
run.krate($should_run).default_condition(builder.config.compiler_docs)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
@ -705,11 +701,6 @@ macro_rules! tool_doc {
|
||||
|
||||
let compiler = builder.compiler(stage, builder.config.build);
|
||||
|
||||
if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
|
||||
builder.info("\tskipping - compiler/tool docs disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
// Build rustc docs so that we generate relative links.
|
||||
builder.ensure(Rustc { stage, target });
|
||||
|
||||
|
@ -763,7 +763,7 @@ impl Step for RustdocJSStd {
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/test/rustdoc-js-std")
|
||||
run.suite_path("src/test/rustdoc-js-std")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
@ -783,6 +783,17 @@ impl Step for RustdocJSStd {
|
||||
.arg(builder.doc_out(self.target))
|
||||
.arg("--test-folder")
|
||||
.arg(builder.src.join("src/test/rustdoc-js-std"));
|
||||
for path in &builder.paths {
|
||||
if let Some(p) =
|
||||
util::is_valid_test_suite_arg(path, "src/test/rustdoc-js-std", builder)
|
||||
{
|
||||
if !p.ends_with(".js") {
|
||||
eprintln!("A non-js file was given: `{}`", path.display());
|
||||
panic!("Cannot run rustdoc-js-std tests");
|
||||
}
|
||||
command.arg("--test-file").arg(path);
|
||||
}
|
||||
}
|
||||
builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage });
|
||||
builder.run(&mut command);
|
||||
} else {
|
||||
@ -803,7 +814,7 @@ impl Step for RustdocJSNotStd {
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/test/rustdoc-js")
|
||||
run.suite_path("src/test/rustdoc-js")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
@ -938,8 +949,12 @@ impl Step for RustdocGUI {
|
||||
.arg("--tests-folder")
|
||||
.arg(builder.build.src.join("src/test/rustdoc-gui"));
|
||||
for path in &builder.paths {
|
||||
if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
|
||||
if name.ends_with(".goml") {
|
||||
if let Some(p) = util::is_valid_test_suite_arg(path, "src/test/rustdoc-gui", builder) {
|
||||
if !p.ends_with(".goml") {
|
||||
eprintln!("A non-goml file was given: `{}`", path.display());
|
||||
panic!("Cannot run rustdoc-gui tests");
|
||||
}
|
||||
if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
|
||||
command.arg("--file").arg(name);
|
||||
}
|
||||
}
|
||||
@ -1416,35 +1431,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
|
||||
// Get test-args by striping suite path
|
||||
let mut test_args: Vec<&str> = paths
|
||||
.iter()
|
||||
.map(|p| match p.strip_prefix(".") {
|
||||
Ok(path) => path,
|
||||
Err(_) => p,
|
||||
})
|
||||
.filter(|p| p.starts_with(suite_path))
|
||||
.filter(|p| {
|
||||
let exists = p.is_dir() || p.is_file();
|
||||
if !exists {
|
||||
if let Some(p) = p.to_str() {
|
||||
builder.info(&format!(
|
||||
"Warning: Skipping \"{}\": not a regular file or directory",
|
||||
p
|
||||
));
|
||||
}
|
||||
}
|
||||
exists
|
||||
})
|
||||
.filter_map(|p| {
|
||||
// Since test suite paths are themselves directories, if we don't
|
||||
// specify a directory or file, we'll get an empty string here
|
||||
// (the result of the test suite directory without its suite prefix).
|
||||
// Therefore, we need to filter these out, as only the first --test-args
|
||||
// flag is respected, so providing an empty --test-args conflicts with
|
||||
// any following it.
|
||||
match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
|
||||
Some(s) if !s.is_empty() => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.filter_map(|p| util::is_valid_test_suite_arg(p, suite_path, builder))
|
||||
.collect();
|
||||
|
||||
test_args.append(&mut builder.config.cmd.test_args());
|
||||
|
@ -286,7 +286,6 @@ macro_rules! bootstrap_tool {
|
||||
$name:ident, $path:expr, $tool_name:expr
|
||||
$(,is_external_tool = $external:expr)*
|
||||
$(,is_unstable_tool = $unstable:expr)*
|
||||
$(,features = $features:expr)*
|
||||
;
|
||||
)+) => {
|
||||
#[derive(Copy, PartialEq, Eq, Clone)]
|
||||
@ -349,12 +348,7 @@ macro_rules! bootstrap_tool {
|
||||
} else {
|
||||
SourceType::InTree
|
||||
},
|
||||
extra_features: {
|
||||
// FIXME(#60643): avoid this lint by using `_`
|
||||
let mut _tmp = Vec::new();
|
||||
$(_tmp.extend($features);)*
|
||||
_tmp
|
||||
},
|
||||
extra_features: vec![],
|
||||
}).expect("expected to build -- essential tool")
|
||||
}
|
||||
}
|
||||
|
@ -310,3 +310,35 @@ pub fn use_host_linker(target: TargetSelection) -> bool {
|
||||
|| target.contains("fuchsia")
|
||||
|| target.contains("bpf"))
|
||||
}
|
||||
|
||||
pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>(
|
||||
path: &'a Path,
|
||||
suite_path: P,
|
||||
builder: &Builder<'_>,
|
||||
) -> Option<&'a str> {
|
||||
let suite_path = suite_path.as_ref();
|
||||
let path = match path.strip_prefix(".") {
|
||||
Ok(p) => p,
|
||||
Err(_) => path,
|
||||
};
|
||||
if !path.starts_with(suite_path) {
|
||||
return None;
|
||||
}
|
||||
let exists = path.is_dir() || path.is_file();
|
||||
if !exists {
|
||||
if let Some(p) = path.to_str() {
|
||||
builder.info(&format!("Warning: Skipping \"{}\": not a regular file or directory", p));
|
||||
}
|
||||
return None;
|
||||
}
|
||||
// Since test suite paths are themselves directories, if we don't
|
||||
// specify a directory or file, we'll get an empty string here
|
||||
// (the result of the test suite directory without its suite prefix).
|
||||
// Therefore, we need to filter these out, as only the first --test-args
|
||||
// flag is respected, so providing an empty --test-args conflicts with
|
||||
// any following it.
|
||||
match path.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
|
||||
Some(s) if !s.is_empty() => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
# `type_changing_struct_update`
|
||||
|
||||
The tracking issue for this feature is: [#86555]
|
||||
|
||||
[#86555]: https://github.com/rust-lang/rust/issues/86555
|
||||
|
||||
------------------------
|
||||
|
||||
This implements [RFC2528]. When turned on, you can create instances of the same struct
|
||||
that have different generic type or lifetime parameters.
|
||||
|
||||
[RFC2528]: https://github.com/rust-lang/rfcs/blob/master/text/2528-type-changing-struct-update-syntax.md
|
||||
|
||||
```rust
|
||||
#![allow(unused_variables, dead_code)]
|
||||
#![feature(type_changing_struct_update)]
|
||||
|
||||
fn main () {
|
||||
struct Foo<T, U> {
|
||||
field1: T,
|
||||
field2: U,
|
||||
}
|
||||
|
||||
let base: Foo<String, i32> = Foo {
|
||||
field1: String::from("hello"),
|
||||
field2: 1234,
|
||||
};
|
||||
let updated: Foo<f64, i32> = Foo {
|
||||
field1: 3.14,
|
||||
..base
|
||||
};
|
||||
}
|
||||
```
|
@ -430,8 +430,9 @@ crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
|
||||
| Res::NonMacroAttr(_)
|
||||
| Res::Err => return res.def_id(),
|
||||
Res::Def(
|
||||
TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy
|
||||
| Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator,
|
||||
TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst
|
||||
| InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure
|
||||
| Generator,
|
||||
id,
|
||||
) => return id,
|
||||
};
|
||||
|
@ -265,9 +265,9 @@ crate fn create_config(
|
||||
// Closures' tables come from their outermost function,
|
||||
// as they are part of the same "inference environment".
|
||||
// This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`)
|
||||
let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
|
||||
if outer_def_id != def_id {
|
||||
return tcx.typeck(outer_def_id);
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
|
||||
if typeck_root_def_id != def_id {
|
||||
return tcx.typeck(typeck_root_def_id);
|
||||
}
|
||||
|
||||
let hir = tcx.hir();
|
||||
|
@ -134,6 +134,7 @@ impl From<DefKind> for ItemType {
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Field
|
||||
| DefKind::LifetimeParam
|
||||
|
@ -1937,7 +1937,8 @@ fn resolution_failure(
|
||||
| Use
|
||||
| LifetimeParam
|
||||
| Ctor(_, _)
|
||||
| AnonConst => {
|
||||
| AnonConst
|
||||
| InlineConst => {
|
||||
let note = assoc_item_not_allowed(res);
|
||||
if let Some(span) = sp {
|
||||
diag.span_label(span, ¬e);
|
||||
|
@ -1,12 +0,0 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/feature-gate-type_changing_struct_update.rs:20:11
|
||||
|
|
||||
LL | ..m1
|
||||
| ^^ expected struct `State2`, found struct `State1`
|
||||
|
|
||||
= note: expected struct `Machine<State2>`
|
||||
found struct `Machine<State1>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
12
src/test/ui/inline-const/const-expr-inference.rs
Normal file
12
src/test/ui/inline-const/const-expr-inference.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(inline_const)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
pub fn todo<T>() -> T {
|
||||
const { todo!() }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: usize = const { 0 };
|
||||
}
|
30
src/test/ui/inline-const/const-expr-lifetime-err.rs
Normal file
30
src/test/ui/inline-const/const-expr-lifetime-err.rs
Normal file
@ -0,0 +1,30 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(inline_const)]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
||||
|
||||
impl<'a, T: ?Sized> InvariantRef<'a, T> {
|
||||
pub const fn new(r: &'a T) -> Self {
|
||||
InvariantRef(r, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> InvariantRef<'a, ()> {
|
||||
pub const NEW: Self = InvariantRef::new(&());
|
||||
}
|
||||
|
||||
fn equate<T>(x: T, y: T){}
|
||||
|
||||
fn foo<'a>() {
|
||||
let y = ();
|
||||
equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
|
||||
//~^ ERROR `y` does not live long enough [E0597]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo();
|
||||
}
|
18
src/test/ui/inline-const/const-expr-lifetime-err.stderr
Normal file
18
src/test/ui/inline-const/const-expr-lifetime-err.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error[E0597]: `y` does not live long enough
|
||||
--> $DIR/const-expr-lifetime-err.rs:24:30
|
||||
|
|
||||
LL | fn foo<'a>() {
|
||||
| -- lifetime `'a` defined here
|
||||
LL | let y = ();
|
||||
LL | equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
|
||||
| ------------------^^-
|
||||
| | |
|
||||
| | borrowed value does not live long enough
|
||||
| argument requires that `y` is borrowed for `'a`
|
||||
LL |
|
||||
LL | }
|
||||
| - `y` dropped here while still borrowed
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
36
src/test/ui/inline-const/const-expr-lifetime.rs
Normal file
36
src/test/ui/inline-const/const-expr-lifetime.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// run-pass
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(inline_const)]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
|
||||
fn issue_78174() {
|
||||
let foo = const { "foo" };
|
||||
assert_eq!(foo, "foo");
|
||||
}
|
||||
|
||||
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
||||
|
||||
impl<'a, T: ?Sized> InvariantRef<'a, T> {
|
||||
pub const fn new(r: &'a T) -> Self {
|
||||
InvariantRef(r, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_invariant_ref<'a>() -> InvariantRef<'a, ()> {
|
||||
const { InvariantRef::<'a, ()>::new(&()) }
|
||||
}
|
||||
|
||||
fn get_invariant_ref2<'a>() -> InvariantRef<'a, ()> {
|
||||
// Try some type inference
|
||||
const { InvariantRef::new(&()) }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
issue_78174();
|
||||
get_invariant_ref();
|
||||
get_invariant_ref2();
|
||||
}
|
12
src/test/ui/inline-const/const-match-pat-inference.rs
Normal file
12
src/test/ui/inline-const/const-match-pat-inference.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(inline_const)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
fn main() {
|
||||
match 1u64 {
|
||||
0 => (),
|
||||
const { 0 + 1 } => (),
|
||||
const { 2 - 1 } ..= const { u64::MAX } => (),
|
||||
}
|
||||
}
|
34
src/test/ui/inline-const/const-match-pat-lifetime-err.rs
Normal file
34
src/test/ui/inline-const/const-match-pat-lifetime-err.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// ignore-test
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(inline_const)]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
||||
|
||||
impl<'a, T: ?Sized> InvariantRef<'a, T> {
|
||||
pub const fn new(r: &'a T) -> Self {
|
||||
InvariantRef(r, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> InvariantRef<'a, ()> {
|
||||
pub const NEW: Self = InvariantRef::new(&());
|
||||
}
|
||||
|
||||
fn match_invariant_ref<'a>() {
|
||||
let y = ();
|
||||
match InvariantRef::new(&y) {
|
||||
//~^ ERROR `y` does not live long enough [E0597]
|
||||
// FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without
|
||||
// const block)
|
||||
const { InvariantRef::<'a>::NEW } => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match_invariant_ref();
|
||||
}
|
36
src/test/ui/inline-const/const-match-pat-lifetime.rs
Normal file
36
src/test/ui/inline-const/const-match-pat-lifetime.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// run-pass
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(inline_const)]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
|
||||
fn issue_78174() {
|
||||
match "foo" {
|
||||
const { concat!("fo", "o") } => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
||||
|
||||
impl<'a, T: ?Sized> InvariantRef<'a, T> {
|
||||
pub const fn new(r: &'a T) -> Self {
|
||||
InvariantRef(r, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_invariant_ref<'a>() {
|
||||
match const { InvariantRef::<'a, _>::new(&()) } {
|
||||
const { InvariantRef::<'a, ()>::new(&()) } => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
issue_78174();
|
||||
match_invariant_ref();
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
// gate-test-type_changing_struct_update
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Machine<S> {
|
||||
state: S,
|
||||
@ -17,9 +19,10 @@ fn update_to_state2() {
|
||||
};
|
||||
let m2: Machine<State2> = Machine {
|
||||
state: State2,
|
||||
..m1 //~ ERROR mismatched types
|
||||
..m1
|
||||
//~^ ERROR type changing struct updating is experimental [E0658]
|
||||
//~| ERROR mismatched types [E0308]
|
||||
};
|
||||
// FIXME: this should trigger feature gate
|
||||
assert_eq!(State2, m2.state);
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
error[E0658]: type changing struct updating is experimental
|
||||
--> $DIR/feature-gate.rs:22:11
|
||||
|
|
||||
LL | ..m1
|
||||
| ^^
|
||||
|
|
||||
= note: see issue #86555 <https://github.com/rust-lang/rust/issues/86555> for more information
|
||||
= help: add `#![feature(type_changing_struct_update)]` to the crate attributes to enable
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/feature-gate.rs:22:11
|
||||
|
|
||||
LL | ..m1
|
||||
| ^^ expected struct `State2`, found struct `State1`
|
||||
|
|
||||
= note: expected struct `Machine<State2>`
|
||||
found struct `Machine<State1>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0658.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
@ -0,0 +1,43 @@
|
||||
#![feature(type_changing_struct_update)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Machine<'a, S> {
|
||||
state: S,
|
||||
lt_str: &'a str,
|
||||
common_field: i32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct State1;
|
||||
#[derive(Clone)]
|
||||
struct State2;
|
||||
|
||||
fn update_to_state2() {
|
||||
let s = String::from("hello");
|
||||
let m1: Machine<State1> = Machine {
|
||||
state: State1,
|
||||
lt_str: &s,
|
||||
//~^ ERROR `s` does not live long enough [E0597]
|
||||
// FIXME: The error here actually comes from line 34. The
|
||||
// span of the error message should be corrected to line 34
|
||||
common_field: 2,
|
||||
};
|
||||
// update lifetime
|
||||
let m3: Machine<'static, State1> = Machine {
|
||||
lt_str: "hello, too",
|
||||
..m1.clone()
|
||||
};
|
||||
// update lifetime and type
|
||||
let m4: Machine<'static, State2> = Machine {
|
||||
state: State2,
|
||||
lt_str: "hello, again",
|
||||
..m1.clone()
|
||||
};
|
||||
// updating to `static should fail.
|
||||
let m2: Machine<'static, State1> = Machine {
|
||||
..m1
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,15 @@
|
||||
error[E0597]: `s` does not live long enough
|
||||
--> $DIR/lifetime-update.rs:20:17
|
||||
|
|
||||
LL | lt_str: &s,
|
||||
| ^^ borrowed value does not live long enough
|
||||
...
|
||||
LL | let m2: Machine<'static, State1> = Machine {
|
||||
| ------------------------ type annotation requires that `s` is borrowed for `'static`
|
||||
...
|
||||
LL | }
|
||||
| - `s` dropped here while still borrowed
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
@ -0,0 +1,57 @@
|
||||
#![feature(type_changing_struct_update)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Machine<'a, S, M> {
|
||||
state: S,
|
||||
message: M,
|
||||
lt_str: &'a str,
|
||||
common_field: i32,
|
||||
}
|
||||
|
||||
struct State1;
|
||||
struct State2;
|
||||
|
||||
struct Message1;
|
||||
struct Message2;
|
||||
|
||||
fn update() {
|
||||
let m1: Machine<State1, Message1> = Machine {
|
||||
state: State1,
|
||||
message: Message1,
|
||||
lt_str: "hello",
|
||||
common_field: 2,
|
||||
};
|
||||
// single type update
|
||||
let m2: Machine<State2, Message1> = Machine {
|
||||
state: State2,
|
||||
..m1
|
||||
};
|
||||
// multiple type update
|
||||
let m3: Machine<State2, Message2> = Machine {
|
||||
state: State2,
|
||||
message: Message2,
|
||||
..m1
|
||||
};
|
||||
}
|
||||
|
||||
fn fail_update() {
|
||||
let m1: Machine<f64, f64> = Machine {
|
||||
state: 3.2,
|
||||
message: 6.4,
|
||||
lt_str: "hello",
|
||||
common_field: 2,
|
||||
};
|
||||
// single type update fail
|
||||
let m2: Machine<i32, f64> = Machine {
|
||||
..m1
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
};
|
||||
// multiple type update fail
|
||||
let m3 = Machine::<i32, i32> {
|
||||
..m1
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| ERROR mismatched types [E0308]
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,30 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-generic-update.rs:46:11
|
||||
|
|
||||
LL | ..m1
|
||||
| ^^ field type mismatch: Machine.state
|
||||
|
|
||||
= note: expected type `i32`
|
||||
found type `f64`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-generic-update.rs:51:11
|
||||
|
|
||||
LL | ..m1
|
||||
| ^^ field type mismatch: Machine.state
|
||||
|
|
||||
= note: expected type `i32`
|
||||
found type `f64`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-generic-update.rs:51:11
|
||||
|
|
||||
LL | ..m1
|
||||
| ^^ field type mismatch: Machine.message
|
||||
|
|
||||
= note: expected type `i32`
|
||||
found type `f64`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -1065,7 +1065,10 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
|
||||
PatKind::Path(path) => {
|
||||
#[allow(clippy::match_same_arms)]
|
||||
let id = match cx.qpath_res(path, pat.hir_id) {
|
||||
Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return,
|
||||
Res::Def(
|
||||
DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
|
||||
_,
|
||||
) => return,
|
||||
Res::Def(_, id) => id,
|
||||
_ => return,
|
||||
};
|
||||
|
@ -401,7 +401,8 @@ function showHelp() {
|
||||
console.log(" --doc-folder [PATH] : location of the generated doc folder");
|
||||
console.log(" --help : show this message then quit");
|
||||
console.log(" --crate-name [STRING] : crate name to be used");
|
||||
console.log(" --test-file [PATH] : location of the JS test file");
|
||||
console.log(" --test-file [PATHs] : location of the JS test files (can be called " +
|
||||
"multiple times)");
|
||||
console.log(" --test-folder [PATH] : location of the JS tests folder");
|
||||
console.log(" --resource-suffix [STRING] : suffix to refer to the correct files");
|
||||
}
|
||||
@ -412,7 +413,7 @@ function parseOptions(args) {
|
||||
"resource_suffix": "",
|
||||
"doc_folder": "",
|
||||
"test_folder": "",
|
||||
"test_file": "",
|
||||
"test_file": [],
|
||||
};
|
||||
var correspondences = {
|
||||
"--resource-suffix": "resource_suffix",
|
||||
@ -429,7 +430,11 @@ function parseOptions(args) {
|
||||
console.log("Missing argument after `" + args[i - 1] + "` option.");
|
||||
return null;
|
||||
}
|
||||
opts[correspondences[args[i - 1]]] = args[i];
|
||||
if (args[i - 1] !== "--test-file") {
|
||||
opts[correspondences[args[i - 1]]] = args[i];
|
||||
} else {
|
||||
opts[correspondences[args[i - 1]]].push(args[i]);
|
||||
}
|
||||
} else if (args[i] === "--help") {
|
||||
showHelp();
|
||||
process.exit(0);
|
||||
@ -471,9 +476,10 @@ function main(argv) {
|
||||
var errors = 0;
|
||||
|
||||
if (opts["test_file"].length !== 0) {
|
||||
errors += checkFile(opts["test_file"], opts, loaded, index);
|
||||
}
|
||||
if (opts["test_folder"].length !== 0) {
|
||||
opts["test_file"].forEach(function(file) {
|
||||
errors += checkFile(file, opts, loaded, index);
|
||||
});
|
||||
} else if (opts["test_folder"].length !== 0) {
|
||||
fs.readdirSync(opts["test_folder"]).forEach(function(file) {
|
||||
if (!file.endsWith(".js")) {
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user