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:
bors 2021-11-09 20:09:53 +00:00
commit 8b09ba6a5d
69 changed files with 1129 additions and 234 deletions

View File

@ -408,7 +408,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let param = generics.type_param(&param_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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -42,6 +42,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
| DefKind::Static
| DefKind::ConstParam
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::AssocConst
),
"Unexpected DefKind: {:?}",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
_ => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -618,6 +618,7 @@ impl EmbargoVisitor<'tcx> {
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::Field
| DefKind::GlobalAsm
| DefKind::Impl

View File

@ -967,6 +967,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm

View File

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

View File

@ -739,6 +739,7 @@ impl<'tcx> SaveContext<'tcx> {
| HirDefKind::ForeignMod
| HirDefKind::LifetimeParam
| HirDefKind::AnonConst
| HirDefKind::InlineConst
| HirDefKind::Use
| HirDefKind::Field
| HirDefKind::GlobalAsm

View File

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

View File

@ -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={:?}",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -134,6 +134,7 @@ impl From<DefKind> for ItemType {
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam

View File

@ -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, &note);

View File

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

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

View 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();
}

View 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`.

View 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();
}

View 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 } => (),
}
}

View 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();
}

View 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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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