Auto merge of #113370 - compiler-errors:rollup-8gvyy8e, r=compiler-errors
Rollup of 8 pull requests Successful merges: - #113010 (rust-installer & rls: remove exclusion from rustfmt & tidy ) - #113317 ( -Ztrait-solver=next: stop depending on old solver) - #113319 (`TypeParameterDefinition` always require a `DefId`) - #113320 (Add some extra information to opaque type cycle errors) - #113321 (Move `ty::ConstKind` to `rustc_type_ir`) - #113337 (Winnow specialized impls during selection in new solver) - #113355 (Move most coverage code out of `rustc_codegen_ssa`) - #113356 (Add support for NetBSD/riscv64 aka. riscv64gc-unknown-netbsd.) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5dac6b320b
84 changed files with 1988 additions and 1412 deletions
|
@ -706,7 +706,6 @@ fn codegen_stmt<'tcx>(
|
|||
let times = fx
|
||||
.monomorphize(times)
|
||||
.eval(fx.tcx, ParamEnv::reveal_all())
|
||||
.kind()
|
||||
.try_to_bits(fx.tcx.data_layout.pointer_size)
|
||||
.unwrap();
|
||||
if operand.layout().size.bytes() == 0 {
|
||||
|
|
|
@ -1,69 +1,11 @@
|
|||
use gccjit::RValue;
|
||||
use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::coverage::{
|
||||
CodeRegion,
|
||||
CounterValueReference,
|
||||
ExpressionOperandId,
|
||||
InjectedExpressionId,
|
||||
Op,
|
||||
};
|
||||
use rustc_codegen_ssa::traits::CoverageInfoBuilderMethods;
|
||||
use rustc_middle::mir::Coverage;
|
||||
use rustc_middle::ty::Instance;
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::context::CodegenCx;
|
||||
|
||||
impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
fn set_function_source_hash(
|
||||
&mut self,
|
||||
_instance: Instance<'tcx>,
|
||||
_function_source_hash: u64,
|
||||
) -> bool {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn add_coverage_counter(&mut self, _instance: Instance<'tcx>, _id: CounterValueReference, _region: CodeRegion) -> bool {
|
||||
fn add_coverage(&mut self, _instance: Instance<'tcx>, _coverage: &Coverage) {
|
||||
// TODO(antoyo)
|
||||
false
|
||||
}
|
||||
|
||||
fn add_coverage_counter_expression(&mut self, _instance: Instance<'tcx>, _id: InjectedExpressionId, _lhs: ExpressionOperandId, _op: Op, _rhs: ExpressionOperandId, _region: Option<CodeRegion>) -> bool {
|
||||
// TODO(antoyo)
|
||||
false
|
||||
}
|
||||
|
||||
fn add_coverage_unreachable(&mut self, _instance: Instance<'tcx>, _region: CodeRegion) -> bool {
|
||||
// TODO(antoyo)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
fn coverageinfo_finalize(&self) {
|
||||
// TODO(antoyo)
|
||||
}
|
||||
|
||||
fn get_pgo_func_name_var(&self, _instance: Instance<'tcx>) -> RValue<'gcc> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
/// Functions with MIR-based coverage are normally codegenned _only_ if
|
||||
/// called. LLVM coverage tools typically expect every function to be
|
||||
/// defined (even if unused), with at least one call to LLVM intrinsic
|
||||
/// `instrprof.increment`.
|
||||
///
|
||||
/// Codegen a small function that will never be called, with one counter
|
||||
/// that will never be incremented.
|
||||
///
|
||||
/// For used/called functions, the coverageinfo was already added to the
|
||||
/// `function_coverage_map` (keyed by function `Instance`) during codegen.
|
||||
/// But in this case, since the unused function was _not_ previously
|
||||
/// codegenned, collect the coverage `CodeRegion`s from the MIR and add
|
||||
/// them. The first `CodeRegion` is used to add a single counter, with the
|
||||
/// same counter ID used in the injected `instrprof.increment` intrinsic
|
||||
/// call. Since the function is never called, all other `CodeRegion`s can be
|
||||
/// added as `unreachable_region`s.
|
||||
fn define_unused_fn(&self, _def_id: DefId) {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
pub use super::ffi::*;
|
||||
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::coverage::{
|
||||
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId,
|
||||
InjectedExpressionIndex, MappedExpressionIndex, Op,
|
|
@ -1,10 +1,10 @@
|
|||
use crate::common::CodegenCx;
|
||||
use crate::coverageinfo;
|
||||
use crate::coverageinfo::map_data::{Counter, CounterExpression};
|
||||
use crate::llvm;
|
||||
|
||||
use llvm::coverageinfo::CounterMappingRegion;
|
||||
use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression};
|
||||
use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods};
|
||||
use rustc_codegen_ssa::traits::ConstMethods;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
|
@ -3,13 +3,13 @@ use crate::llvm;
|
|||
use crate::abi::Abi;
|
||||
use crate::builder::Builder;
|
||||
use crate::common::CodegenCx;
|
||||
use crate::coverageinfo::map_data::{CounterExpression, FunctionCoverage};
|
||||
|
||||
use libc::c_uint;
|
||||
use llvm::coverageinfo::CounterMappingRegion;
|
||||
use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, FunctionCoverage};
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, CoverageInfoMethods,
|
||||
MiscMethods, StaticMethods,
|
||||
BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods,
|
||||
StaticMethods,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
|
@ -17,16 +17,19 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_llvm::RustString;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::coverage::{
|
||||
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op,
|
||||
CodeRegion, CounterValueReference, CoverageKind, ExpressionOperandId, InjectedExpressionId, Op,
|
||||
};
|
||||
use rustc_middle::mir::Coverage;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::Instance;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::CString;
|
||||
|
||||
mod ffi;
|
||||
pub(crate) mod map_data;
|
||||
pub mod mapgen;
|
||||
|
||||
const UNUSED_FUNCTION_COUNTER_ID: CounterValueReference = CounterValueReference::START;
|
||||
|
@ -53,11 +56,17 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
fn coverageinfo_finalize(&self) {
|
||||
// These methods used to be part of trait `CoverageInfoMethods`, which no longer
|
||||
// exists after most coverage code was moved out of SSA.
|
||||
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
||||
pub(crate) fn coverageinfo_finalize(&self) {
|
||||
mapgen::finalize(self)
|
||||
}
|
||||
|
||||
/// For LLVM codegen, returns a function-specific `Value` for a global
|
||||
/// string, to hold the function name passed to LLVM intrinsic
|
||||
/// `instrprof.increment()`. The `Value` is only created once per instance.
|
||||
/// Multiple invocations with the same instance return the same `Value`.
|
||||
fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
|
||||
if let Some(coverage_context) = self.coverage_context() {
|
||||
debug!("getting pgo_func_name_var for instance={:?}", instance);
|
||||
|
@ -94,6 +103,54 @@ impl<'ll, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
||||
fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage) {
|
||||
let bx = self;
|
||||
|
||||
let Coverage { kind, code_region } = coverage.clone();
|
||||
match kind {
|
||||
CoverageKind::Counter { function_source_hash, id } => {
|
||||
if bx.set_function_source_hash(instance, function_source_hash) {
|
||||
// If `set_function_source_hash()` returned true, the coverage map is enabled,
|
||||
// so continue adding the counter.
|
||||
if let Some(code_region) = code_region {
|
||||
// Note: Some counters do not have code regions, but may still be referenced
|
||||
// from expressions. In that case, don't add the counter to the coverage map,
|
||||
// but do inject the counter intrinsic.
|
||||
bx.add_coverage_counter(instance, id, code_region);
|
||||
}
|
||||
|
||||
let coverageinfo = bx.tcx().coverageinfo(instance.def);
|
||||
|
||||
let fn_name = bx.get_pgo_func_name_var(instance);
|
||||
let hash = bx.const_u64(function_source_hash);
|
||||
let num_counters = bx.const_u32(coverageinfo.num_counters);
|
||||
let index = bx.const_u32(id.zero_based_index());
|
||||
debug!(
|
||||
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
|
||||
fn_name, hash, num_counters, index,
|
||||
);
|
||||
bx.instrprof_increment(fn_name, hash, num_counters, index);
|
||||
}
|
||||
}
|
||||
CoverageKind::Expression { id, lhs, op, rhs } => {
|
||||
bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region);
|
||||
}
|
||||
CoverageKind::Unreachable => {
|
||||
bx.add_coverage_unreachable(
|
||||
instance,
|
||||
code_region.expect("unreachable regions always have code regions"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These methods used to be part of trait `CoverageInfoBuilderMethods`, but
|
||||
// after moving most coverage code out of SSA they are now just ordinary methods.
|
||||
impl<'tcx> Builder<'_, '_, 'tcx> {
|
||||
/// Returns true if the function source hash was added to the coverage map (even if it had
|
||||
/// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is
|
||||
/// not enabled (a coverage map is not being generated).
|
||||
fn set_function_source_hash(
|
||||
&mut self,
|
||||
instance: Instance<'tcx>,
|
||||
|
@ -115,6 +172,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage`
|
||||
/// is not enabled (a coverage map is not being generated).
|
||||
fn add_coverage_counter(
|
||||
&mut self,
|
||||
instance: Instance<'tcx>,
|
||||
|
@ -137,6 +196,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the expression was added to the coverage map; false if
|
||||
/// `-C instrument-coverage` is not enabled (a coverage map is not being generated).
|
||||
fn add_coverage_counter_expression(
|
||||
&mut self,
|
||||
instance: Instance<'tcx>,
|
||||
|
@ -163,6 +224,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the region was added to the coverage map; false if `-C instrument-coverage`
|
||||
/// is not enabled (a coverage map is not being generated).
|
||||
fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool {
|
||||
if let Some(coverage_context) = self.coverage_context() {
|
||||
debug!(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use rustc_codegen_ssa::coverageinfo::map as coverage_map;
|
||||
use crate::coverageinfo::map_data as coverage_map;
|
||||
|
||||
use super::debuginfo::{
|
||||
DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
pub mod ffi;
|
||||
pub mod map;
|
|
@ -48,7 +48,6 @@ pub mod back;
|
|||
pub mod base;
|
||||
pub mod codegen_attrs;
|
||||
pub mod common;
|
||||
pub mod coverageinfo;
|
||||
pub mod debuginfo;
|
||||
pub mod errors;
|
||||
pub mod glue;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use crate::traits::*;
|
||||
|
||||
use rustc_middle::mir::coverage::*;
|
||||
use rustc_middle::mir::Coverage;
|
||||
use rustc_middle::mir::SourceScope;
|
||||
|
||||
use super::FunctionCx;
|
||||
|
||||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage, scope: SourceScope) {
|
||||
pub fn codegen_coverage(&self, bx: &mut Bx, coverage: &Coverage, scope: SourceScope) {
|
||||
// Determine the instance that coverage data was originally generated for.
|
||||
let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) {
|
||||
self.monomorphize(inlined)
|
||||
|
@ -15,41 +14,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
self.instance
|
||||
};
|
||||
|
||||
let Coverage { kind, code_region } = coverage;
|
||||
match kind {
|
||||
CoverageKind::Counter { function_source_hash, id } => {
|
||||
if bx.set_function_source_hash(instance, function_source_hash) {
|
||||
// If `set_function_source_hash()` returned true, the coverage map is enabled,
|
||||
// so continue adding the counter.
|
||||
if let Some(code_region) = code_region {
|
||||
// Note: Some counters do not have code regions, but may still be referenced
|
||||
// from expressions. In that case, don't add the counter to the coverage map,
|
||||
// but do inject the counter intrinsic.
|
||||
bx.add_coverage_counter(instance, id, code_region);
|
||||
}
|
||||
|
||||
let coverageinfo = bx.tcx().coverageinfo(instance.def);
|
||||
|
||||
let fn_name = bx.get_pgo_func_name_var(instance);
|
||||
let hash = bx.const_u64(function_source_hash);
|
||||
let num_counters = bx.const_u32(coverageinfo.num_counters);
|
||||
let index = bx.const_u32(id.zero_based_index());
|
||||
debug!(
|
||||
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
|
||||
fn_name, hash, num_counters, index,
|
||||
);
|
||||
bx.instrprof_increment(fn_name, hash, num_counters, index);
|
||||
}
|
||||
}
|
||||
CoverageKind::Expression { id, lhs, op, rhs } => {
|
||||
bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region);
|
||||
}
|
||||
CoverageKind::Unreachable => {
|
||||
bx.add_coverage_unreachable(
|
||||
instance,
|
||||
code_region.expect("unreachable regions always have code regions"),
|
||||
);
|
||||
}
|
||||
}
|
||||
// Handle the coverage info in a backend-specific way.
|
||||
bx.add_coverage(instance, coverage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
mir::StatementKind::Coverage(box ref coverage) => {
|
||||
self.codegen_coverage(bx, coverage.clone(), statement.source_info.scope);
|
||||
self.codegen_coverage(bx, coverage, statement.source_info.scope);
|
||||
}
|
||||
mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
|
||||
let op_val = self.codegen_operand(bx, op);
|
||||
|
|
|
@ -1,57 +1,11 @@
|
|||
use super::BackendTypes;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::coverage::*;
|
||||
use rustc_middle::mir::Coverage;
|
||||
use rustc_middle::ty::Instance;
|
||||
|
||||
pub trait CoverageInfoMethods<'tcx>: BackendTypes {
|
||||
fn coverageinfo_finalize(&self);
|
||||
|
||||
/// Codegen a small function that will never be called, with one counter
|
||||
/// that will never be incremented, that gives LLVM coverage tools a
|
||||
/// function definition it needs in order to resolve coverage map references
|
||||
/// to unused functions. This is necessary so unused functions will appear
|
||||
/// as uncovered (coverage execution count `0`) in LLVM coverage reports.
|
||||
fn define_unused_fn(&self, def_id: DefId);
|
||||
|
||||
/// For LLVM codegen, returns a function-specific `Value` for a global
|
||||
/// string, to hold the function name passed to LLVM intrinsic
|
||||
/// `instrprof.increment()`. The `Value` is only created once per instance.
|
||||
/// Multiple invocations with the same instance return the same `Value`.
|
||||
fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value;
|
||||
}
|
||||
|
||||
pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
|
||||
/// Returns true if the function source hash was added to the coverage map (even if it had
|
||||
/// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is
|
||||
/// not enabled (a coverage map is not being generated).
|
||||
fn set_function_source_hash(
|
||||
&mut self,
|
||||
instance: Instance<'tcx>,
|
||||
function_source_hash: u64,
|
||||
) -> bool;
|
||||
|
||||
/// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage`
|
||||
/// is not enabled (a coverage map is not being generated).
|
||||
fn add_coverage_counter(
|
||||
&mut self,
|
||||
instance: Instance<'tcx>,
|
||||
index: CounterValueReference,
|
||||
region: CodeRegion,
|
||||
) -> bool;
|
||||
|
||||
/// Returns true if the expression was added to the coverage map; false if
|
||||
/// `-C instrument-coverage` is not enabled (a coverage map is not being generated).
|
||||
fn add_coverage_counter_expression(
|
||||
&mut self,
|
||||
instance: Instance<'tcx>,
|
||||
id: InjectedExpressionId,
|
||||
lhs: ExpressionOperandId,
|
||||
op: Op,
|
||||
rhs: ExpressionOperandId,
|
||||
region: Option<CodeRegion>,
|
||||
) -> bool;
|
||||
|
||||
/// Returns true if the region was added to the coverage map; false if `-C instrument-coverage`
|
||||
/// is not enabled (a coverage map is not being generated).
|
||||
fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool;
|
||||
/// Handle the MIR coverage info in a backend-specific way.
|
||||
///
|
||||
/// This can potentially be a no-op in backends that don't support
|
||||
/// coverage instrumentation.
|
||||
fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAs
|
|||
pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods};
|
||||
pub use self::builder::{BuilderMethods, OverflowOp};
|
||||
pub use self::consts::ConstMethods;
|
||||
pub use self::coverageinfo::{CoverageInfoBuilderMethods, CoverageInfoMethods};
|
||||
pub use self::coverageinfo::CoverageInfoBuilderMethods;
|
||||
pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods};
|
||||
pub use self::declare::PreDefineMethods;
|
||||
pub use self::intrinsic::IntrinsicCallMethods;
|
||||
|
@ -59,7 +59,6 @@ pub trait CodegenMethods<'tcx>:
|
|||
+ MiscMethods<'tcx>
|
||||
+ ConstMethods<'tcx>
|
||||
+ StaticMethods
|
||||
+ CoverageInfoMethods<'tcx>
|
||||
+ DebugInfoMethods<'tcx>
|
||||
+ AsmMethods<'tcx>
|
||||
+ PreDefineMethods<'tcx>
|
||||
|
@ -75,7 +74,6 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where
|
|||
+ MiscMethods<'tcx>
|
||||
+ ConstMethods<'tcx>
|
||||
+ StaticMethods
|
||||
+ CoverageInfoMethods<'tcx>
|
||||
+ DebugInfoMethods<'tcx>
|
||||
+ AsmMethods<'tcx>
|
||||
+ PreDefineMethods<'tcx>
|
||||
|
|
|
@ -254,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
type BreakTy = ty::GenericArg<'tcx>;
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
|
||||
if let Some(origin) = self.0.type_var_origin(ty)
|
||||
&& let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
|
||||
&& let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, def_id) =
|
||||
origin.kind
|
||||
&& let generics = self.0.tcx.generics_of(self.1)
|
||||
&& let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
|
||||
|
|
|
@ -265,9 +265,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
kind: UnderspecifiedArgKind::Type {
|
||||
prefix: "type parameter".into(),
|
||||
},
|
||||
parent: def_id.and_then(|def_id| {
|
||||
InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id)
|
||||
}),
|
||||
parent: InferenceDiagnosticsParentData::for_def_id(
|
||||
self.tcx, def_id,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1110,7 +1110,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeParameterDefinition(
|
||||
param.name,
|
||||
Some(param.def_id),
|
||||
param.def_id,
|
||||
),
|
||||
span,
|
||||
},
|
||||
|
|
|
@ -21,23 +21,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
recursion_depth: usize,
|
||||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||
) -> Ty<'tcx> {
|
||||
if self.next_trait_solver() {
|
||||
// FIXME(-Ztrait-solver=next): Instead of branching here,
|
||||
// completely change the normalization routine with the new solver.
|
||||
//
|
||||
// The new solver correctly handles projection equality so this hack
|
||||
// is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate`
|
||||
// not `PredicateKind::Clause(ClauseKind::Projection(..))` as in the new solver
|
||||
// `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
|
||||
return projection_ty.to_ty(self.tcx);
|
||||
} else {
|
||||
debug_assert!(!self.next_trait_solver());
|
||||
let def_id = projection_ty.def_id;
|
||||
let ty_var = self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::NormalizeProjectionType,
|
||||
span: self.tcx.def_span(def_id),
|
||||
});
|
||||
let projection =
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
|
||||
let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
|
||||
ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
|
||||
)));
|
||||
let obligation =
|
||||
|
@ -45,5 +35,4 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
obligations.push(obligation);
|
||||
ty_var
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ pub enum TypeVariableOriginKind {
|
|||
NormalizeProjectionType,
|
||||
TypeInference,
|
||||
OpaqueTypeInference(DefId),
|
||||
TypeParameterDefinition(Symbol, Option<DefId>),
|
||||
TypeParameterDefinition(Symbol, DefId),
|
||||
|
||||
/// One of the upvars or closure kind parameters in a `ClosureSubsts`
|
||||
/// (before it has been determined).
|
||||
|
|
|
@ -2329,7 +2329,7 @@ impl<'tcx> ConstantKind<'tcx> {
|
|||
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
match self {
|
||||
Self::Ty(c) => {
|
||||
if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) {
|
||||
if let Some(val) = c.try_eval_for_mir(tcx, param_env) {
|
||||
match val {
|
||||
Ok(val) => Self::Val(val, c.ty()),
|
||||
Err(guar) => Self::Ty(ty::Const::new_error(tcx, guar, self.ty())),
|
||||
|
@ -2867,7 +2867,7 @@ fn pretty_print_const_value<'tcx>(
|
|||
}
|
||||
}
|
||||
(ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
|
||||
let n = n.kind().try_to_bits(tcx.data_layout.pointer_size).unwrap();
|
||||
let n = n.try_to_bits(tcx.data_layout.pointer_size).unwrap();
|
||||
// cast is ok because we already checked for pointer size (32 or 64 bit) above
|
||||
let range = AllocRange { start: offset, size: Size::from_bytes(n) };
|
||||
let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap();
|
||||
|
|
|
@ -588,6 +588,10 @@ pub enum SelectionError<'tcx> {
|
|||
/// Signaling that an error has already been emitted, to avoid
|
||||
/// multiple errors being shown.
|
||||
ErrorReporting,
|
||||
/// Computing an opaque type's hidden type caused an error (e.g. a cycle error).
|
||||
/// We can thus not know whether the hidden type implements an auto trait, so
|
||||
/// we should not presume anything about it.
|
||||
OpaqueTypeAutoTraitLeakageUnknown(DefId),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, TypeVisitable, Lift)]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::middle::resolve_bound_vars as rbv;
|
||||
use crate::mir::interpret::LitToConstInput;
|
||||
use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
|
||||
use crate::mir::interpret::{AllocId, ConstValue, LitToConstInput, Scalar};
|
||||
use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_error_messages::MultiSpan;
|
||||
use rustc_hir as hir;
|
||||
|
@ -14,9 +14,13 @@ mod valtree;
|
|||
|
||||
pub use int::*;
|
||||
pub use kind::*;
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::Size;
|
||||
pub use valtree::*;
|
||||
|
||||
use super::sty::ConstKind;
|
||||
|
||||
/// Use this rather than `ConstData`, whenever possible.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
|
||||
#[rustc_pass_by_value]
|
||||
|
@ -32,6 +36,16 @@ pub struct ConstData<'tcx> {
|
|||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
static_assert_size!(ConstData<'_>, 40);
|
||||
|
||||
enum EvalMode {
|
||||
Typeck,
|
||||
Mir,
|
||||
}
|
||||
|
||||
enum EvalResult<'tcx> {
|
||||
ValTree(ty::ValTree<'tcx>),
|
||||
ConstVal(ConstValue<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> Const<'tcx> {
|
||||
#[inline]
|
||||
pub fn ty(self) -> Ty<'tcx> {
|
||||
|
@ -40,7 +54,7 @@ impl<'tcx> Const<'tcx> {
|
|||
|
||||
#[inline]
|
||||
pub fn kind(self) -> ConstKind<'tcx> {
|
||||
self.0.kind
|
||||
self.0.kind.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -293,12 +307,12 @@ impl<'tcx> Const<'tcx> {
|
|||
assert_eq!(self.ty(), ty);
|
||||
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
|
||||
// if `ty` does not depend on generic parameters, use an empty param_env
|
||||
self.kind().eval(tcx, param_env).try_to_bits(size)
|
||||
self.eval(tcx, param_env).try_to_bits(size)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
|
||||
self.kind().eval(tcx, param_env).try_to_bool()
|
||||
self.eval(tcx, param_env).try_to_bool()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -307,14 +321,14 @@ impl<'tcx> Const<'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<u64> {
|
||||
self.kind().eval(tcx, param_env).try_to_target_usize(tcx)
|
||||
self.eval(tcx, param_env).try_to_target_usize(tcx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
|
||||
/// unevaluated constant.
|
||||
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
|
||||
if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) {
|
||||
if let Some(val) = self.try_eval_for_typeck(tcx, param_env) {
|
||||
match val {
|
||||
Ok(val) => ty::Const::new_value(tcx, val, self.ty()),
|
||||
Err(guar) => ty::Const::new_error(tcx, guar, self.ty()),
|
||||
|
@ -339,6 +353,138 @@ impl<'tcx> Const<'tcx> {
|
|||
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
|
||||
/// return `None`.
|
||||
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
|
||||
pub fn try_eval_for_mir(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
|
||||
match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
|
||||
Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
|
||||
Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
|
||||
Some(Err(e)) => Some(Err(e)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
|
||||
/// return `None`.
|
||||
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
|
||||
pub fn try_eval_for_typeck(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
|
||||
match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
|
||||
Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
|
||||
Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
|
||||
Some(Err(e)) => Some(Err(e)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_eval_inner(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
eval_mode: EvalMode,
|
||||
) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
|
||||
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
|
||||
if let ConstKind::Unevaluated(unevaluated) = self.kind() {
|
||||
use crate::mir::interpret::ErrorHandled;
|
||||
|
||||
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
|
||||
// also does later, but we want to do it before checking for
|
||||
// inference variables.
|
||||
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
|
||||
// so that we don't try to invoke this query with
|
||||
// any region variables.
|
||||
|
||||
// HACK(eddyb) when the query key would contain inference variables,
|
||||
// attempt using identity substs and `ParamEnv` instead, that will succeed
|
||||
// when the expression doesn't depend on any parameters.
|
||||
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
|
||||
// we can call `infcx.const_eval_resolve` which handles inference variables.
|
||||
let param_env_and = if (param_env, unevaluated).has_non_region_infer() {
|
||||
tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst {
|
||||
def: unevaluated.def,
|
||||
substs: InternalSubsts::identity_for_item(tcx, unevaluated.def),
|
||||
})
|
||||
} else {
|
||||
tcx.erase_regions(param_env)
|
||||
.with_reveal_all_normalized(tcx)
|
||||
.and(tcx.erase_regions(unevaluated))
|
||||
};
|
||||
|
||||
// FIXME(eddyb) maybe the `const_eval_*` methods should take
|
||||
// `ty::ParamEnvAnd` instead of having them separate.
|
||||
let (param_env, unevaluated) = param_env_and.into_parts();
|
||||
// try to resolve e.g. associated constants to their definition on an impl, and then
|
||||
// evaluate the const.
|
||||
match eval_mode {
|
||||
EvalMode::Typeck => {
|
||||
match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
|
||||
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
|
||||
// and we use the original type, so nothing from `substs`
|
||||
// (which may be identity substs, see above),
|
||||
// can leak through `val` into the const we return.
|
||||
Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
|
||||
Err(ErrorHandled::TooGeneric) => None,
|
||||
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
|
||||
}
|
||||
}
|
||||
EvalMode::Mir => {
|
||||
match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) {
|
||||
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
|
||||
// and we use the original type, so nothing from `substs`
|
||||
// (which may be identity substs, see above),
|
||||
// can leak through `val` into the const we return.
|
||||
Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
|
||||
Err(ErrorHandled::TooGeneric) => None,
|
||||
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
|
||||
if let ConstKind::Value(val) = self.kind() { Some(val) } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
|
||||
self.try_to_value()?.try_to_scalar()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
|
||||
self.try_to_value()?.try_to_scalar_int()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_bits(self, size: Size) -> Option<u128> {
|
||||
self.try_to_scalar_int()?.to_bits(size).ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_bool(self) -> Option<bool> {
|
||||
self.try_to_scalar_int()?.try_into().ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_value()?.try_to_target_usize(tcx)
|
||||
}
|
||||
|
||||
pub fn is_ct_infer(self) -> bool {
|
||||
matches!(self.kind(), ty::ConstKind::Infer(_))
|
||||
}
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
use super::Const;
|
||||
use crate::mir;
|
||||
use crate::mir::interpret::{AllocId, ConstValue, Scalar};
|
||||
use crate::ty::abstract_const::CastKind;
|
||||
use crate::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use crate::ty::ParamEnv;
|
||||
use crate::ty::{self, List, Ty, TyCtxt, TypeVisitableExt};
|
||||
use crate::ty::subst::SubstsRef;
|
||||
use crate::ty::{self, List, Ty};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_target::abi::Size;
|
||||
|
||||
use super::ScalarInt;
|
||||
|
||||
/// An unevaluated (potentially generic) constant used in the type-system.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
|
||||
|
@ -41,45 +35,6 @@ impl<'tcx> UnevaluatedConst<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a constant in Rust.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
#[derive(derive_more::From)]
|
||||
pub enum ConstKind<'tcx> {
|
||||
/// A const generic parameter.
|
||||
Param(ty::ParamConst),
|
||||
|
||||
/// Infer the value of the const.
|
||||
Infer(InferConst<'tcx>),
|
||||
|
||||
/// Bound const variable, used only when preparing a trait query.
|
||||
Bound(ty::DebruijnIndex, ty::BoundVar),
|
||||
|
||||
/// A placeholder const - universally quantified higher-ranked const.
|
||||
Placeholder(ty::PlaceholderConst<'tcx>),
|
||||
|
||||
/// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
|
||||
/// variants when the code is monomorphic enough for that.
|
||||
Unevaluated(UnevaluatedConst<'tcx>),
|
||||
|
||||
/// Used to hold computed value.
|
||||
Value(ty::ValTree<'tcx>),
|
||||
|
||||
/// A placeholder for a const which could not be computed; this is
|
||||
/// propagated to avoid useless error messages.
|
||||
#[from(ignore)]
|
||||
Error(ErrorGuaranteed),
|
||||
|
||||
/// Expr which contains an expression which has partially evaluated items.
|
||||
Expr(Expr<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> From<ty::ConstVid<'tcx>> for ConstKind<'tcx> {
|
||||
fn from(const_vid: ty::ConstVid<'tcx>) -> Self {
|
||||
InferConst::Var(const_vid).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
|
||||
pub enum Expr<'tcx> {
|
||||
|
@ -93,39 +48,7 @@ pub enum Expr<'tcx> {
|
|||
static_assert_size!(Expr<'_>, 24);
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
static_assert_size!(ConstKind<'_>, 32);
|
||||
|
||||
impl<'tcx> ConstKind<'tcx> {
|
||||
#[inline]
|
||||
pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
|
||||
if let ConstKind::Value(val) = self { Some(val) } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
|
||||
self.try_to_value()?.try_to_scalar()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
|
||||
self.try_to_value()?.try_to_scalar_int()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_bits(self, size: Size) -> Option<u128> {
|
||||
self.try_to_scalar_int()?.to_bits(size).ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_bool(self) -> Option<bool> {
|
||||
self.try_to_scalar_int()?.try_into().ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_value()?.try_to_target_usize(tcx)
|
||||
}
|
||||
}
|
||||
static_assert_size!(super::ConstKind<'_>, 32);
|
||||
|
||||
/// An inference variable for a const, for use in const generics.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
|
||||
|
@ -144,124 +67,3 @@ impl<CTX> HashStable<CTX> for InferConst<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum EvalMode {
|
||||
Typeck,
|
||||
Mir,
|
||||
}
|
||||
|
||||
enum EvalResult<'tcx> {
|
||||
ValTree(ty::ValTree<'tcx>),
|
||||
ConstVal(ConstValue<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> ConstKind<'tcx> {
|
||||
#[inline]
|
||||
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
|
||||
/// unevaluated constant.
|
||||
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
|
||||
self.try_eval_for_typeck(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
|
||||
/// return `None`.
|
||||
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
|
||||
pub fn try_eval_for_mir(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
|
||||
match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
|
||||
Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
|
||||
Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
|
||||
Some(Err(e)) => Some(Err(e)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
|
||||
/// return `None`.
|
||||
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
|
||||
pub fn try_eval_for_typeck(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
|
||||
match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
|
||||
Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
|
||||
Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
|
||||
Some(Err(e)) => Some(Err(e)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_eval_inner(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
eval_mode: EvalMode,
|
||||
) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
|
||||
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
|
||||
if let ConstKind::Unevaluated(unevaluated) = self {
|
||||
use crate::mir::interpret::ErrorHandled;
|
||||
|
||||
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
|
||||
// also does later, but we want to do it before checking for
|
||||
// inference variables.
|
||||
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
|
||||
// so that we don't try to invoke this query with
|
||||
// any region variables.
|
||||
|
||||
// HACK(eddyb) when the query key would contain inference variables,
|
||||
// attempt using identity substs and `ParamEnv` instead, that will succeed
|
||||
// when the expression doesn't depend on any parameters.
|
||||
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
|
||||
// we can call `infcx.const_eval_resolve` which handles inference variables.
|
||||
let param_env_and = if (param_env, unevaluated).has_non_region_infer() {
|
||||
tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst {
|
||||
def: unevaluated.def,
|
||||
substs: InternalSubsts::identity_for_item(tcx, unevaluated.def),
|
||||
})
|
||||
} else {
|
||||
tcx.erase_regions(param_env)
|
||||
.with_reveal_all_normalized(tcx)
|
||||
.and(tcx.erase_regions(unevaluated))
|
||||
};
|
||||
|
||||
// FIXME(eddyb) maybe the `const_eval_*` methods should take
|
||||
// `ty::ParamEnvAnd` instead of having them separate.
|
||||
let (param_env, unevaluated) = param_env_and.into_parts();
|
||||
// try to resolve e.g. associated constants to their definition on an impl, and then
|
||||
// evaluate the const.
|
||||
match eval_mode {
|
||||
EvalMode::Typeck => {
|
||||
match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
|
||||
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
|
||||
// and we use the original type, so nothing from `substs`
|
||||
// (which may be identity substs, see above),
|
||||
// can leak through `val` into the const we return.
|
||||
Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
|
||||
Err(ErrorHandled::TooGeneric) => None,
|
||||
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
|
||||
}
|
||||
}
|
||||
EvalMode::Mir => {
|
||||
match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) {
|
||||
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
|
||||
// and we use the original type, so nothing from `substs`
|
||||
// (which may be identity substs, see above),
|
||||
// can leak through `val` into the const we return.
|
||||
Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
|
||||
Err(ErrorHandled::TooGeneric) => None,
|
||||
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,6 +108,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
type PredicateKind = ty::PredicateKind<'tcx>;
|
||||
type AllocId = crate::mir::interpret::AllocId;
|
||||
|
||||
type InferConst = ty::InferConst<'tcx>;
|
||||
type AliasConst = ty::UnevaluatedConst<'tcx>;
|
||||
type ParamConst = ty::ParamConst;
|
||||
type BoundConst = ty::BoundVar;
|
||||
type PlaceholderConst = ty::PlaceholderConst<'tcx>;
|
||||
type ValueConst = ty::ValTree<'tcx>;
|
||||
type ExprConst = ty::Expr<'tcx>;
|
||||
|
||||
type EarlyBoundRegion = ty::EarlyBoundRegion;
|
||||
type BoundRegion = ty::BoundRegion;
|
||||
type FreeRegion = ty::FreeRegion;
|
||||
|
|
|
@ -170,7 +170,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
|
|||
match self {
|
||||
Self::ConstIsZero(c) => {
|
||||
let c = ty::EarlyBinder::bind(c).subst(tcx, substs);
|
||||
let pred = match c.kind().try_to_target_usize(tcx) {
|
||||
let pred = match c.try_to_target_usize(tcx) {
|
||||
Some(0) => Self::True,
|
||||
Some(1..) => Self::False,
|
||||
None => Self::ConstIsZero(c),
|
||||
|
|
|
@ -197,7 +197,7 @@ fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedP
|
|||
|
||||
// If we can evaluate the array length before having a `ParamEnv`, then
|
||||
// we can simplify the predicate. This is an optimization.
|
||||
Array(ty, len) => match len.kind().try_to_target_usize(tcx) {
|
||||
Array(ty, len) => match len.try_to_target_usize(tcx) {
|
||||
Some(0) => InhabitedPredicate::True,
|
||||
Some(1..) => ty.inhabited_predicate(tcx),
|
||||
None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
|
||||
|
|
|
@ -410,8 +410,8 @@ impl<'tcx> Instance<'tcx> {
|
|||
) -> Instance<'tcx> {
|
||||
match ty::Instance::resolve(tcx, param_env, def_id, substs) {
|
||||
Ok(Some(instance)) => instance,
|
||||
_ => bug!(
|
||||
"failed to resolve instance for {}",
|
||||
instance => bug!(
|
||||
"failed to resolve instance for {}: {instance:#?}",
|
||||
tcx.def_path_str_with_substs(def_id, substs)
|
||||
),
|
||||
}
|
||||
|
|
|
@ -66,6 +66,10 @@ use std::{fmt, str};
|
|||
|
||||
pub use crate::ty::diagnostics::*;
|
||||
pub use rustc_type_ir::AliasKind::*;
|
||||
pub use rustc_type_ir::ConstKind::{
|
||||
Bound as BoundCt, Error as ErrorCt, Expr as ExprCt, Infer as InferCt, Param as ParamCt,
|
||||
Placeholder as PlaceholderCt, Unevaluated, Value,
|
||||
};
|
||||
pub use rustc_type_ir::DynKind::*;
|
||||
pub use rustc_type_ir::InferTy::*;
|
||||
pub use rustc_type_ir::RegionKind::*;
|
||||
|
@ -81,7 +85,7 @@ pub use self::closure::{
|
|||
CAPTURE_STRUCT_LOCAL,
|
||||
};
|
||||
pub use self::consts::{
|
||||
Const, ConstData, ConstInt, ConstKind, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree,
|
||||
Const, ConstData, ConstInt, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree,
|
||||
};
|
||||
pub use self::context::{
|
||||
tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed,
|
||||
|
@ -93,7 +97,7 @@ pub use self::rvalue_scopes::RvalueScopes;
|
|||
pub use self::sty::BoundRegionKind::*;
|
||||
pub use self::sty::{
|
||||
AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
|
||||
BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid,
|
||||
BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstKind, ConstVid,
|
||||
EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
|
||||
FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts,
|
||||
InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialPredicate,
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
|
|||
use rustc_hir::def::Namespace;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_target::abi::TyAndLayout;
|
||||
use rustc_type_ir::ConstKind;
|
||||
|
||||
use std::fmt;
|
||||
use std::ops::ControlFlow;
|
||||
|
@ -241,24 +242,6 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::ConstKind<'tcx> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use ty::ConstKind::*;
|
||||
match self {
|
||||
Param(param) => write!(f, "{param:?}"),
|
||||
Infer(var) => write!(f, "{var:?}"),
|
||||
Bound(debruijn, var) => rustc_type_ir::debug_bound_var(f, *debruijn, *var),
|
||||
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
||||
Unevaluated(uv) => {
|
||||
f.debug_tuple("Unevaluated").field(&uv.substs).field(&uv.def).finish()
|
||||
}
|
||||
Value(valtree) => write!(f, "{valtree:?}"),
|
||||
Error(_) => write!(f, "{{const error}}"),
|
||||
Expr(expr) => write!(f, "{expr:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::BoundTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.kind {
|
||||
|
@ -728,7 +711,18 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
|
|||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
let ty = self.ty().try_fold_with(folder)?;
|
||||
let kind = self.kind().try_fold_with(folder)?;
|
||||
let kind = match self.kind() {
|
||||
ConstKind::Param(p) => ConstKind::Param(p.try_fold_with(folder)?),
|
||||
ConstKind::Infer(i) => ConstKind::Infer(i.try_fold_with(folder)?),
|
||||
ConstKind::Bound(d, b) => {
|
||||
ConstKind::Bound(d.try_fold_with(folder)?, b.try_fold_with(folder)?)
|
||||
}
|
||||
ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?),
|
||||
ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?),
|
||||
ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?),
|
||||
ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?),
|
||||
ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?),
|
||||
};
|
||||
if ty != self.ty() || kind != self.kind() {
|
||||
Ok(folder.interner().mk_ct_from_kind(kind, ty))
|
||||
} else {
|
||||
|
@ -743,7 +737,19 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
|
|||
visitor: &mut V,
|
||||
) -> ControlFlow<V::BreakTy> {
|
||||
self.ty().visit_with(visitor)?;
|
||||
self.kind().visit_with(visitor)
|
||||
match self.kind() {
|
||||
ConstKind::Param(p) => p.visit_with(visitor),
|
||||
ConstKind::Infer(i) => i.visit_with(visitor),
|
||||
ConstKind::Bound(d, b) => {
|
||||
d.visit_with(visitor)?;
|
||||
b.visit_with(visitor)
|
||||
}
|
||||
ConstKind::Placeholder(p) => p.visit_with(visitor),
|
||||
ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
|
||||
ConstKind::Value(v) => v.visit_with(visitor),
|
||||
ConstKind::Error(e) => e.visit_with(visitor),
|
||||
ConstKind::Expr(e) => e.visit_with(visitor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ use std::ops::{ControlFlow, Deref, Range};
|
|||
use ty::util::IntTypeExt;
|
||||
|
||||
use rustc_type_ir::sty::TyKind::*;
|
||||
use rustc_type_ir::ConstKind as IrConstKind;
|
||||
use rustc_type_ir::RegionKind as IrRegionKind;
|
||||
use rustc_type_ir::TyKind as IrTyKind;
|
||||
|
||||
|
@ -40,6 +41,7 @@ use rustc_type_ir::TyKind as IrTyKind;
|
|||
#[rustc_diagnostic_item = "TyKind"]
|
||||
pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
|
||||
pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
|
||||
pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
|
|
|
@ -1306,7 +1306,7 @@ pub fn needs_drop_components<'tcx>(
|
|||
ty::Array(elem_ty, size) => {
|
||||
match needs_drop_components(*elem_ty, target_layout) {
|
||||
Ok(v) if v.is_empty() => Ok(v),
|
||||
res => match size.kind().try_to_bits(target_layout.pointer_size) {
|
||||
res => match size.try_to_bits(target_layout.pointer_size) {
|
||||
// Arrays of size zero don't need drop, even if their element
|
||||
// type does.
|
||||
Some(0) => Ok(SmallVec::new()),
|
||||
|
|
|
@ -126,18 +126,13 @@ where
|
|||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn mk_cycle<Q, Qcx>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
cycle_error: CycleError<Qcx::DepKind>,
|
||||
handler: HandleCycleError,
|
||||
) -> Q::Value
|
||||
fn mk_cycle<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError<Qcx::DepKind>) -> Q::Value
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
{
|
||||
let error = report_cycle(qcx.dep_context().sess(), &cycle_error);
|
||||
handle_cycle_error(query, qcx, &cycle_error, error, handler)
|
||||
handle_cycle_error(query, qcx, &cycle_error, error)
|
||||
}
|
||||
|
||||
fn handle_cycle_error<Q, Qcx>(
|
||||
|
@ -145,14 +140,13 @@ fn handle_cycle_error<Q, Qcx>(
|
|||
qcx: Qcx,
|
||||
cycle_error: &CycleError<Qcx::DepKind>,
|
||||
mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
|
||||
handler: HandleCycleError,
|
||||
) -> Q::Value
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
{
|
||||
use HandleCycleError::*;
|
||||
match handler {
|
||||
match query.handle_cycle_error() {
|
||||
Error => {
|
||||
error.emit();
|
||||
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle)
|
||||
|
@ -277,7 +271,7 @@ where
|
|||
&qcx.current_query_job(),
|
||||
span,
|
||||
);
|
||||
(mk_cycle(query, qcx, error, query.handle_cycle_error()), None)
|
||||
(mk_cycle(query, qcx, error), None)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -314,7 +308,7 @@ where
|
|||
|
||||
(v, Some(index))
|
||||
}
|
||||
Err(cycle) => (mk_cycle(query, qcx, cycle, query.handle_cycle_error()), None),
|
||||
Err(cycle) => (mk_cycle(query, qcx, cycle), None),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,13 @@ pub trait Value<Tcx: DepContext, D: DepKind>: Sized {
|
|||
}
|
||||
|
||||
impl<Tcx: DepContext, T, D: DepKind> Value<Tcx, D> for T {
|
||||
default fn from_cycle_error(tcx: Tcx, _: &[QueryInfo<D>]) -> T {
|
||||
default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>]) -> T {
|
||||
tcx.sess().abort_if_errors();
|
||||
// Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
|
||||
// non-trivial to define it earlier.
|
||||
panic!("Value::from_cycle_error called without errors");
|
||||
panic!(
|
||||
"<{} as Value>::from_cycle_error called without errors: {cycle:#?}",
|
||||
std::any::type_name::<T>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,7 +230,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
|
|||
self.write_str("[")?;
|
||||
self = self.print_type(ty)?;
|
||||
self.write_str("; ")?;
|
||||
if let Some(size) = size.kind().try_to_bits(self.tcx().data_layout.pointer_size) {
|
||||
if let Some(size) = size.try_to_bits(self.tcx().data_layout.pointer_size) {
|
||||
write!(self, "{size}")?
|
||||
} else if let ty::ConstKind::Param(param) = size.kind() {
|
||||
self = param.print(self)?
|
||||
|
|
|
@ -112,7 +112,7 @@ fn encode_const<'tcx>(
|
|||
let _ = write!(s, "{value}");
|
||||
}
|
||||
|
||||
if let Some(scalar_int) = c.kind().try_to_scalar_int() {
|
||||
if let Some(scalar_int) = c.try_to_scalar_int() {
|
||||
let signed = c.ty().is_signed();
|
||||
match scalar_int.size().bits() {
|
||||
8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0),
|
||||
|
@ -504,8 +504,7 @@ fn encode_ty<'tcx>(
|
|||
let _ = write!(
|
||||
s,
|
||||
"{}",
|
||||
&len.kind()
|
||||
.try_to_scalar()
|
||||
&len.try_to_scalar()
|
||||
.unwrap()
|
||||
.to_u64()
|
||||
.unwrap_or_else(|_| panic!("failed to convert length to u64"))
|
||||
|
@ -815,7 +814,6 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
|
|||
|
||||
ty::Array(ty0, len) => {
|
||||
let len = len
|
||||
.kind()
|
||||
.try_to_scalar()
|
||||
.unwrap()
|
||||
.to_u64()
|
||||
|
|
|
@ -651,7 +651,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
|
|||
.builtin_deref(true)
|
||||
.expect("tried to dereference on non-ptr type")
|
||||
.ty;
|
||||
// FIXME: add an assert that we only do this for valtrees.
|
||||
// FIXME(const_generics): add an assert that we only do this for valtrees.
|
||||
let dereferenced_const = self.tcx.mk_ct_from_kind(ct.kind(), pointee_ty);
|
||||
self = dereferenced_const.print(self)?;
|
||||
}
|
||||
|
|
|
@ -1325,6 +1325,7 @@ supported_targets! {
|
|||
("armv7-unknown-netbsd-eabihf", armv7_unknown_netbsd_eabihf),
|
||||
("i686-unknown-netbsd", i686_unknown_netbsd),
|
||||
("powerpc-unknown-netbsd", powerpc_unknown_netbsd),
|
||||
("riscv64gc-unknown-netbsd", riscv64gc_unknown_netbsd),
|
||||
("sparc64-unknown-netbsd", sparc64_unknown_netbsd),
|
||||
("x86_64-unknown-netbsd", x86_64_unknown_netbsd),
|
||||
|
||||
|
|
19
compiler/rustc_target/src/spec/riscv64gc_unknown_netbsd.rs
Normal file
19
compiler/rustc_target/src/spec/riscv64gc_unknown_netbsd.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use crate::spec::{CodeModel, Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Target {
|
||||
Target {
|
||||
llvm_target: "riscv64-unknown-netbsd".into(),
|
||||
pointer_width: 64,
|
||||
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
|
||||
arch: "riscv64".into(),
|
||||
options: TargetOptions {
|
||||
code_model: Some(CodeModel::Medium),
|
||||
cpu: "generic-rv64".into(),
|
||||
features: "+m,+a,+f,+d,+c".into(),
|
||||
llvm_abiname: "lp64d".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "__mcount".into(),
|
||||
..super::netbsd_base::opts()
|
||||
},
|
||||
}
|
||||
}
|
|
@ -52,7 +52,11 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
|
|||
let mut i = 0;
|
||||
while i < candidates.len() {
|
||||
let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
|
||||
candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])
|
||||
candidate_should_be_dropped_in_favor_of(
|
||||
ecx.tcx(),
|
||||
&candidates[i],
|
||||
&candidates[j],
|
||||
)
|
||||
});
|
||||
if should_drop_i {
|
||||
candidates.swap_remove(i);
|
||||
|
@ -160,12 +164,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn candidate_should_be_dropped_in_favor_of<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
victim: &Candidate<'tcx>,
|
||||
other: &Candidate<'tcx>,
|
||||
) -> bool {
|
||||
match (victim.source, other.source) {
|
||||
(CandidateSource::ParamEnv(i), CandidateSource::ParamEnv(j)) => i >= j,
|
||||
(CandidateSource::ParamEnv(victim_idx), CandidateSource::ParamEnv(other_idx)) => {
|
||||
victim_idx >= other_idx
|
||||
}
|
||||
(_, CandidateSource::ParamEnv(_)) => true,
|
||||
(CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => {
|
||||
tcx.specializes((other_def_id, victim_def_id))
|
||||
&& other.result.value.certainty == Certainty::Yes
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,6 +159,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
|
|||
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
||||
let reveal = self.at.param_env.reveal();
|
||||
let infcx = self.at.infcx;
|
||||
debug_assert_eq!(ty, infcx.shallow_resolve(ty));
|
||||
if !needs_normalization(&ty, reveal) {
|
||||
return Ok(ty);
|
||||
}
|
||||
|
@ -192,6 +193,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
|
|||
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
|
||||
let reveal = self.at.param_env.reveal();
|
||||
let infcx = self.at.infcx;
|
||||
debug_assert_eq!(ct, infcx.shallow_resolve(ct));
|
||||
if !needs_normalization(&ct, reveal) {
|
||||
return Ok(ct);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ use std::fmt::Debug;
|
|||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use super::query::evaluate_obligation::InferCtxtExt;
|
||||
use super::NormalizeExt;
|
||||
|
||||
/// Whether we do the orphan check relative to this crate or
|
||||
|
@ -290,6 +291,20 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
|
|||
) -> bool {
|
||||
let infcx = selcx.infcx;
|
||||
|
||||
let obligation_guaranteed_to_fail = move |obligation: &PredicateObligation<'tcx>| {
|
||||
if infcx.next_trait_solver() {
|
||||
infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply())
|
||||
} else {
|
||||
// We use `evaluate_root_obligation` to correctly track
|
||||
// intercrate ambiguity clauses. We do not need this in the
|
||||
// new solver.
|
||||
selcx.evaluate_root_obligation(obligation).map_or(
|
||||
false, // Overflow has occurred, and treat the obligation as possibly holding.
|
||||
|result| !result.may_apply(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
|
@ -297,12 +312,7 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
|
|||
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate)
|
||||
})
|
||||
.chain(obligations)
|
||||
.find(|o| {
|
||||
selcx.evaluate_root_obligation(o).map_or(
|
||||
false, // Overflow has occurred, and treat the obligation as possibly holding.
|
||||
|result| !result.may_apply(),
|
||||
)
|
||||
});
|
||||
.find(obligation_guaranteed_to_fail);
|
||||
|
||||
if let Some(failing_obligation) = opt_failing_obligation {
|
||||
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
|
||||
|
|
|
@ -30,7 +30,7 @@ use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
|||
use rustc_infer::infer::{InferOk, TypeTrace};
|
||||
use rustc_middle::traits::select::OverflowError;
|
||||
use rustc_middle::traits::solve::Goal;
|
||||
use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
|
||||
use rustc_middle::traits::{DefiningAnchor, SelectionOutputTypeParameterMismatch};
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
|
||||
|
@ -1152,6 +1152,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => self.report_opaque_type_auto_trait_leakage(
|
||||
&obligation,
|
||||
def_id,
|
||||
),
|
||||
|
||||
TraitNotObjectSafe(did) => {
|
||||
let violations = self.tcx.object_safety_violations(did);
|
||||
report_object_safety_error(self.tcx, span, did, violations)
|
||||
|
@ -1170,16 +1175,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
// Already reported in the query.
|
||||
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) => {
|
||||
// FIXME(eddyb) remove this once `ErrorGuaranteed` becomes a proof token.
|
||||
self.tcx.sess.delay_span_bug(span, "`ErrorGuaranteed` without an error");
|
||||
return;
|
||||
}
|
||||
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) |
|
||||
// Already reported.
|
||||
Overflow(OverflowError::Error(_)) => {
|
||||
self.tcx.sess.delay_span_bug(span, "`OverflowError` has been reported");
|
||||
return;
|
||||
}
|
||||
Overflow(OverflowError::Error(_)) => return,
|
||||
|
||||
Overflow(_) => {
|
||||
bug!("overflow should be handled before the `report_selection_error` path");
|
||||
}
|
||||
|
@ -1471,6 +1470,12 @@ trait InferCtxtPrivExt<'tcx> {
|
|||
terr: TypeError<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
|
||||
|
||||
fn report_opaque_type_auto_trait_leakage(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
|
||||
|
||||
fn report_type_parameter_mismatch_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
|
@ -2646,11 +2651,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() {
|
||||
if let ty::Param(_) = *ty.kind() {
|
||||
let infcx = self.infcx;
|
||||
*self.var_map.entry(ty).or_insert_with(|| {
|
||||
infcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: DUMMY_SP,
|
||||
})
|
||||
})
|
||||
|
@ -3192,6 +3197,39 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
fn report_opaque_type_auto_trait_leakage(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
|
||||
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
|
||||
format!("opaque type")
|
||||
}
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||
format!("`{}`", self.tcx.def_path_debug_str(def_id))
|
||||
}
|
||||
};
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
obligation.cause.span,
|
||||
format!("cannot check whether the hidden type of {name} satisfies auto traits"),
|
||||
);
|
||||
err.span_note(self.tcx.def_span(def_id), "opaque type is declared here");
|
||||
match self.defining_use_anchor {
|
||||
DefiningAnchor::Bubble | DefiningAnchor::Error => {}
|
||||
DefiningAnchor::Bind(bind) => {
|
||||
err.span_note(
|
||||
self.tcx.def_ident_span(bind).unwrap_or_else(|| self.tcx.def_span(bind)),
|
||||
"this item depends on auto traits of the hidden type, \
|
||||
but may also be registering the hidden type. \
|
||||
This is not supported right now. \
|
||||
You can try moving the opaque type and the item that actually registers a hidden type into a new submodule".to_string(),
|
||||
);
|
||||
}
|
||||
};
|
||||
err
|
||||
}
|
||||
|
||||
fn report_type_parameter_mismatch_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
|
|
|
@ -278,7 +278,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
// Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
|
||||
if let ty::Array(aty, len) = self_ty.kind() {
|
||||
flags.push((sym::_Self, Some("[]".to_string())));
|
||||
let len = len.kind().try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
|
||||
let len = len.try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
|
||||
flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
|
||||
if let Some(n) = len {
|
||||
flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));
|
||||
|
|
|
@ -528,7 +528,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
debug!("equating consts:\nc1= {:?}\nc2= {:?}", c1, c2);
|
||||
|
||||
use rustc_hir::def::DefKind;
|
||||
use ty::ConstKind::Unevaluated;
|
||||
use ty::Unevaluated;
|
||||
match (c1.kind(), c2.kind()) {
|
||||
(Unevaluated(a), Unevaluated(b))
|
||||
if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst =>
|
||||
|
|
|
@ -447,6 +447,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
depth: usize,
|
||||
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
|
||||
) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||
debug_assert!(!selcx.infcx.next_trait_solver());
|
||||
AssocTypeNormalizer {
|
||||
selcx,
|
||||
param_env,
|
||||
|
@ -1122,6 +1123,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
|||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||
) -> Result<Option<Term<'tcx>>, InProgress> {
|
||||
let infcx = selcx.infcx;
|
||||
debug_assert!(!selcx.infcx.next_trait_solver());
|
||||
// Don't use the projection cache in intercrate mode -
|
||||
// the `infcx` may be re-used between intercrate in non-intercrate
|
||||
// mode, which could lead to using incorrect cache results.
|
||||
|
|
|
@ -97,6 +97,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
}
|
||||
})
|
||||
} else {
|
||||
assert!(!self.intercrate);
|
||||
let c_pred = self.canonicalize_query_keep_static(
|
||||
param_env.and(obligation.predicate),
|
||||
&mut _orig_values,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::solve;
|
||||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::wf;
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
@ -6,6 +7,7 @@ use rustc_infer::infer::canonical::Canonical;
|
|||
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
|
||||
use rustc_infer::traits::query::OutlivesBound;
|
||||
use rustc_middle::infer::canonical::CanonicalQueryResponse;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
|
@ -164,19 +166,29 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
|
|||
|
||||
// We lazily compute the outlives components as
|
||||
// `select_all_or_error` constrains inference variables.
|
||||
let implied_bounds = outlives_bounds
|
||||
.into_iter()
|
||||
.flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
|
||||
ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
|
||||
let mut implied_bounds = Vec::new();
|
||||
for ty::OutlivesPredicate(a, r_b) in outlives_bounds {
|
||||
match a.unpack() {
|
||||
ty::GenericArgKind::Lifetime(r_a) => {
|
||||
implied_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a))
|
||||
}
|
||||
ty::GenericArgKind::Type(ty_a) => {
|
||||
let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
|
||||
let mut ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
|
||||
// Need to manually normalize in the new solver as `wf::obligations` does not.
|
||||
if ocx.infcx.next_trait_solver() {
|
||||
ty_a = solve::deeply_normalize(
|
||||
ocx.infcx.at(&ObligationCause::dummy(), param_env),
|
||||
ty_a,
|
||||
)
|
||||
.map_err(|_errs| NoSolution)?;
|
||||
}
|
||||
let mut components = smallvec![];
|
||||
push_outlives_components(tcx, ty_a, &mut components);
|
||||
implied_bounds_from_components(r_b, components)
|
||||
implied_bounds.extend(implied_bounds_from_components(r_b, components))
|
||||
}
|
||||
ty::GenericArgKind::Const(_) => unreachable!(),
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(implied_bounds)
|
||||
}
|
||||
|
|
|
@ -388,7 +388,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// `FnPtr`, when we wanted to report that it doesn't implement `Trait`.
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn reject_fn_ptr_impls(
|
||||
&self,
|
||||
&mut self,
|
||||
impl_def_id: DefId,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
impl_self_ty: Ty<'tcx>,
|
||||
|
@ -464,7 +464,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
|
||||
})),
|
||||
);
|
||||
if let Ok(r) = self.infcx.evaluate_obligation(&obligation) {
|
||||
if let Ok(r) = self.evaluate_root_obligation(&obligation) {
|
||||
if !r.may_apply() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
AutoImplCandidate => {
|
||||
let data = self.confirm_auto_impl_candidate(obligation);
|
||||
let data = self.confirm_auto_impl_candidate(obligation)?;
|
||||
ImplSource::Builtin(data)
|
||||
}
|
||||
|
||||
|
@ -376,12 +376,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
fn confirm_auto_impl_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> Vec<PredicateObligation<'tcx>> {
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
debug!(?obligation, "confirm_auto_impl_candidate");
|
||||
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty());
|
||||
let types = self.constituent_types_for_ty(self_ty);
|
||||
self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types)
|
||||
let types = self.constituent_types_for_ty(self_ty)?;
|
||||
Ok(self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types))
|
||||
}
|
||||
|
||||
/// See `confirm_auto_impl_candidate`.
|
||||
|
|
|
@ -34,8 +34,6 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_infer::traits::TraitEngine;
|
||||
use rustc_infer::traits::TraitEngineExt;
|
||||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
|
@ -312,6 +310,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
||||
debug_assert!(!self.infcx.next_trait_solver());
|
||||
// Watch out for overflow. This intentionally bypasses (and does
|
||||
// not update) the cache.
|
||||
self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
|
||||
|
@ -526,21 +525,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// Evaluates whether the obligation `obligation` can be satisfied
|
||||
/// and returns an `EvaluationResult`. This is meant for the
|
||||
/// *initial* call.
|
||||
///
|
||||
/// Do not use this directly, use `infcx.evaluate_obligation` instead.
|
||||
pub fn evaluate_root_obligation(
|
||||
&mut self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
debug_assert!(!self.infcx.next_trait_solver());
|
||||
self.evaluation_probe(|this| {
|
||||
let goal =
|
||||
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
|
||||
let mut result = if this.infcx.next_trait_solver() {
|
||||
this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])?
|
||||
} else {
|
||||
this.evaluate_predicate_recursively(
|
||||
let mut result = this.evaluate_predicate_recursively(
|
||||
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
|
||||
obligation.clone(),
|
||||
)?
|
||||
};
|
||||
)?;
|
||||
// If the predicate has done any inference, then downgrade the
|
||||
// result to ambiguous.
|
||||
if this.infcx.shallow_resolve(goal) != goal {
|
||||
|
@ -587,9 +585,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
where
|
||||
I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
|
||||
{
|
||||
if self.infcx.next_trait_solver() {
|
||||
self.evaluate_predicates_recursively_in_new_solver(predicates)
|
||||
} else {
|
||||
let mut result = EvaluatedToOk;
|
||||
for mut obligation in predicates {
|
||||
obligation.set_depth_from_parent(stack.depth());
|
||||
|
@ -604,26 +599,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluates the predicates using the new solver when `-Ztrait-solver=next` is enabled
|
||||
fn evaluate_predicates_recursively_in_new_solver(
|
||||
&mut self,
|
||||
predicates: impl IntoIterator<Item = PredicateObligation<'tcx>>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(self.infcx);
|
||||
fulfill_cx.register_predicate_obligations(self.infcx, predicates);
|
||||
// True errors
|
||||
// FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK?
|
||||
if !fulfill_cx.select_where_possible(self.infcx).is_empty() {
|
||||
return Ok(EvaluatedToErr);
|
||||
}
|
||||
if !fulfill_cx.select_all_or_error(self.infcx).is_empty() {
|
||||
return Ok(EvaluatedToAmbig);
|
||||
}
|
||||
// Regions and opaques are handled in the `evaluation_probe` by looking at the snapshot
|
||||
Ok(EvaluatedToOk)
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
level = "debug",
|
||||
|
@ -636,6 +611,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
previous_stack: TraitObligationStackList<'o, 'tcx>,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
debug_assert!(!self.infcx.next_trait_solver());
|
||||
// `previous_stack` stores a `TraitObligation`, while `obligation` is
|
||||
// a `PredicateObligation`. These are distinct types, so we can't
|
||||
// use any `Option` combinator method that would force them to be
|
||||
|
@ -897,7 +873,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
);
|
||||
|
||||
use rustc_hir::def::DefKind;
|
||||
use ty::ConstKind::Unevaluated;
|
||||
use ty::Unevaluated;
|
||||
match (c1.kind(), c2.kind()) {
|
||||
(Unevaluated(a), Unevaluated(b))
|
||||
if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst =>
|
||||
|
@ -1179,6 +1155,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
debug_assert!(!self.infcx.next_trait_solver());
|
||||
// In intercrate mode, whenever any of the generics are unbound,
|
||||
// there can always be an impl. Even if there are no impls in
|
||||
// this crate, perhaps the type would be unified with
|
||||
|
@ -2294,8 +2271,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
fn constituent_types_for_ty(
|
||||
&self,
|
||||
t: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
|
||||
match *t.skip_binder().kind() {
|
||||
) -> Result<ty::Binder<'tcx, Vec<Ty<'tcx>>>, SelectionError<'tcx>> {
|
||||
Ok(match *t.skip_binder().kind() {
|
||||
ty::Uint(_)
|
||||
| ty::Int(_)
|
||||
| ty::Bool
|
||||
|
@ -2359,12 +2336,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
}
|
||||
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
let ty = self.tcx().type_of(def_id);
|
||||
if ty.skip_binder().references_error() {
|
||||
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
|
||||
}
|
||||
// We can resolve the `impl Trait` to its concrete type,
|
||||
// which enforces a DAG between the functions requiring
|
||||
// the auto trait bounds in question.
|
||||
t.rebind(vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)])
|
||||
}
|
||||
t.rebind(vec![ty.subst(self.tcx(), substs)])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn collect_predicates_for_types(
|
||||
|
|
|
@ -302,6 +302,16 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
// Do not normalize `wf` obligations with the new solver.
|
||||
//
|
||||
// The current deep normalization routine with the new solver does not
|
||||
// handle ambiguity and the new solver correctly deals with unnnormalized goals.
|
||||
// If the user relies on normalized types, e.g. for `fn implied_outlives_bounds`,
|
||||
// it is their responsibility to normalize while avoiding ambiguity.
|
||||
if infcx.next_trait_solver() {
|
||||
return self.out;
|
||||
}
|
||||
|
||||
let cause = self.cause(traits::WellFormed(None));
|
||||
let param_env = self.param_env;
|
||||
let mut obligations = Vec::with_capacity(self.out.len());
|
||||
|
|
|
@ -57,11 +57,19 @@ pub trait Interner: Sized {
|
|||
type ParamTy: Clone + Debug + Hash + Ord;
|
||||
type BoundTy: Clone + Debug + Hash + Ord;
|
||||
type PlaceholderType: Clone + Debug + Hash + Ord;
|
||||
type InferTy: Clone + Debug + Hash + Ord;
|
||||
type ErrorGuaranteed: Clone + Debug + Hash + Ord;
|
||||
type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
|
||||
type AllocId: Clone + Debug + Hash + Ord;
|
||||
|
||||
type InferConst: Clone + Debug + Hash + Ord;
|
||||
type AliasConst: Clone + Debug + Hash + Ord;
|
||||
type PlaceholderConst: Clone + Debug + Hash + Ord;
|
||||
type ParamConst: Clone + Debug + Hash + Ord;
|
||||
type BoundConst: Clone + Debug + Hash + Ord;
|
||||
type InferTy: Clone + Debug + Hash + Ord;
|
||||
type ValueConst: Clone + Debug + Hash + Ord;
|
||||
type ExprConst: Clone + Debug + Hash + Ord;
|
||||
|
||||
type EarlyBoundRegion: Clone + Debug + Hash + Ord;
|
||||
type BoundRegion: Clone + Debug + Hash + Ord;
|
||||
type FreeRegion: Clone + Debug + Hash + Ord;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use crate::fold::{FallibleTypeFolder, TypeFoldable};
|
||||
use crate::visit::{TypeVisitable, TypeVisitor};
|
||||
use crate::{FloatTy, IntTy, Interner, UintTy};
|
||||
use crate::{ConstKind, FloatTy, IntTy, Interner, UintTy};
|
||||
use rustc_data_structures::functor::IdFunctor;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
|
@ -182,3 +182,21 @@ impl fmt::Debug for FloatTy {
|
|||
write!(f, "{}", self.name_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> fmt::Debug for ConstKind<I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use ConstKind::*;
|
||||
match self {
|
||||
Param(param) => write!(f, "{param:?}"),
|
||||
Infer(var) => write!(f, "{var:?}"),
|
||||
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()),
|
||||
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
||||
Unevaluated(uv) => {
|
||||
write!(f, "{uv:?}")
|
||||
}
|
||||
Value(valtree) => write!(f, "{valtree:?}"),
|
||||
Error(_) => write!(f, "{{const error}}"),
|
||||
Expr(expr) => write!(f, "{expr:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -876,6 +876,224 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a constant in Rust.
|
||||
// #[derive(derive_more::From)]
|
||||
pub enum ConstKind<I: Interner> {
|
||||
/// A const generic parameter.
|
||||
Param(I::ParamConst),
|
||||
|
||||
/// Infer the value of the const.
|
||||
Infer(I::InferConst),
|
||||
|
||||
/// Bound const variable, used only when preparing a trait query.
|
||||
Bound(DebruijnIndex, I::BoundConst),
|
||||
|
||||
/// A placeholder const - universally quantified higher-ranked const.
|
||||
Placeholder(I::PlaceholderConst),
|
||||
|
||||
/// An unnormalized const item such as an anon const or assoc const or free const item.
|
||||
/// Right now anything other than anon consts does not actually work properly but this
|
||||
/// should
|
||||
Unevaluated(I::AliasConst),
|
||||
|
||||
/// Used to hold computed value.
|
||||
Value(I::ValueConst),
|
||||
|
||||
/// A placeholder for a const which could not be computed; this is
|
||||
/// propagated to avoid useless error messages.
|
||||
Error(I::ErrorGuaranteed),
|
||||
|
||||
/// Unevaluated non-const-item, used by `feature(generic_const_exprs)` to represent
|
||||
/// const arguments such as `N + 1` or `foo(N)`
|
||||
Expr(I::ExprConst),
|
||||
}
|
||||
|
||||
const fn const_kind_discriminant<I: Interner>(value: &ConstKind<I>) -> usize {
|
||||
match value {
|
||||
ConstKind::Param(_) => 0,
|
||||
ConstKind::Infer(_) => 1,
|
||||
ConstKind::Bound(_, _) => 2,
|
||||
ConstKind::Placeholder(_) => 3,
|
||||
ConstKind::Unevaluated(_) => 4,
|
||||
ConstKind::Value(_) => 5,
|
||||
ConstKind::Error(_) => 6,
|
||||
ConstKind::Expr(_) => 7,
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> hash::Hash for ConstKind<I> {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
const_kind_discriminant(self).hash(state);
|
||||
match self {
|
||||
ConstKind::Param(p) => p.hash(state),
|
||||
ConstKind::Infer(i) => i.hash(state),
|
||||
ConstKind::Bound(d, b) => {
|
||||
d.hash(state);
|
||||
b.hash(state);
|
||||
}
|
||||
ConstKind::Placeholder(p) => p.hash(state),
|
||||
ConstKind::Unevaluated(u) => u.hash(state),
|
||||
ConstKind::Value(v) => v.hash(state),
|
||||
ConstKind::Error(e) => e.hash(state),
|
||||
ConstKind::Expr(e) => e.hash(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ConstKind<I>
|
||||
where
|
||||
I::ParamConst: HashStable<CTX>,
|
||||
I::InferConst: HashStable<CTX>,
|
||||
I::BoundConst: HashStable<CTX>,
|
||||
I::PlaceholderConst: HashStable<CTX>,
|
||||
I::AliasConst: HashStable<CTX>,
|
||||
I::ValueConst: HashStable<CTX>,
|
||||
I::ErrorGuaranteed: HashStable<CTX>,
|
||||
I::ExprConst: HashStable<CTX>,
|
||||
{
|
||||
fn hash_stable(
|
||||
&self,
|
||||
hcx: &mut CTX,
|
||||
hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
|
||||
) {
|
||||
const_kind_discriminant(self).hash_stable(hcx, hasher);
|
||||
match self {
|
||||
ConstKind::Param(p) => p.hash_stable(hcx, hasher),
|
||||
ConstKind::Infer(i) => i.hash_stable(hcx, hasher),
|
||||
ConstKind::Bound(d, b) => {
|
||||
d.hash_stable(hcx, hasher);
|
||||
b.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstKind::Placeholder(p) => p.hash_stable(hcx, hasher),
|
||||
ConstKind::Unevaluated(u) => u.hash_stable(hcx, hasher),
|
||||
ConstKind::Value(v) => v.hash_stable(hcx, hasher),
|
||||
ConstKind::Error(e) => e.hash_stable(hcx, hasher),
|
||||
ConstKind::Expr(e) => e.hash_stable(hcx, hasher),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for ConstKind<I>
|
||||
where
|
||||
I::ParamConst: Decodable<D>,
|
||||
I::InferConst: Decodable<D>,
|
||||
I::BoundConst: Decodable<D>,
|
||||
I::PlaceholderConst: Decodable<D>,
|
||||
I::AliasConst: Decodable<D>,
|
||||
I::ValueConst: Decodable<D>,
|
||||
I::ErrorGuaranteed: Decodable<D>,
|
||||
I::ExprConst: Decodable<D>,
|
||||
{
|
||||
fn decode(d: &mut D) -> Self {
|
||||
match Decoder::read_usize(d) {
|
||||
0 => ConstKind::Param(Decodable::decode(d)),
|
||||
1 => ConstKind::Infer(Decodable::decode(d)),
|
||||
2 => ConstKind::Bound(Decodable::decode(d), Decodable::decode(d)),
|
||||
3 => ConstKind::Placeholder(Decodable::decode(d)),
|
||||
4 => ConstKind::Unevaluated(Decodable::decode(d)),
|
||||
5 => ConstKind::Value(Decodable::decode(d)),
|
||||
6 => ConstKind::Error(Decodable::decode(d)),
|
||||
7 => ConstKind::Expr(Decodable::decode(d)),
|
||||
_ => panic!(
|
||||
"{}",
|
||||
format!(
|
||||
"invalid enum variant tag while decoding `{}`, expected 0..{}",
|
||||
"ConstKind", 8,
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for ConstKind<I>
|
||||
where
|
||||
I::ParamConst: Encodable<E>,
|
||||
I::InferConst: Encodable<E>,
|
||||
I::BoundConst: Encodable<E>,
|
||||
I::PlaceholderConst: Encodable<E>,
|
||||
I::AliasConst: Encodable<E>,
|
||||
I::ValueConst: Encodable<E>,
|
||||
I::ErrorGuaranteed: Encodable<E>,
|
||||
I::ExprConst: Encodable<E>,
|
||||
{
|
||||
fn encode(&self, e: &mut E) {
|
||||
let disc = const_kind_discriminant(self);
|
||||
match self {
|
||||
ConstKind::Param(p) => e.emit_enum_variant(disc, |e| p.encode(e)),
|
||||
ConstKind::Infer(i) => e.emit_enum_variant(disc, |e| i.encode(e)),
|
||||
ConstKind::Bound(d, b) => e.emit_enum_variant(disc, |e| {
|
||||
d.encode(e);
|
||||
b.encode(e);
|
||||
}),
|
||||
ConstKind::Placeholder(p) => e.emit_enum_variant(disc, |e| p.encode(e)),
|
||||
ConstKind::Unevaluated(u) => e.emit_enum_variant(disc, |e| u.encode(e)),
|
||||
ConstKind::Value(v) => e.emit_enum_variant(disc, |e| v.encode(e)),
|
||||
ConstKind::Error(er) => e.emit_enum_variant(disc, |e| er.encode(e)),
|
||||
ConstKind::Expr(ex) => e.emit_enum_variant(disc, |e| ex.encode(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> PartialOrd for ConstKind<I> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Ord for ConstKind<I> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
const_kind_discriminant(self)
|
||||
.cmp(&const_kind_discriminant(other))
|
||||
.then_with(|| match (self, other) {
|
||||
(ConstKind::Param(p1), ConstKind::Param(p2)) => p1.cmp(p2),
|
||||
(ConstKind::Infer(i1), ConstKind::Infer(i2)) => i1.cmp(i2),
|
||||
(ConstKind::Bound(d1, b1), ConstKind::Bound(d2, b2)) => d1.cmp(d2).then_with(|| b1.cmp(b2)),
|
||||
(ConstKind::Placeholder(p1), ConstKind::Placeholder(p2)) => p1.cmp(p2),
|
||||
(ConstKind::Unevaluated(u1), ConstKind::Unevaluated(u2)) => u1.cmp(u2),
|
||||
(ConstKind::Value(v1), ConstKind::Value(v2)) => v1.cmp(v2),
|
||||
(ConstKind::Error(e1), ConstKind::Error(e2)) => e1.cmp(e2),
|
||||
(ConstKind::Expr(e1), ConstKind::Expr(e2)) => e1.cmp(e2),
|
||||
_ => {
|
||||
debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}");
|
||||
Ordering::Equal
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> PartialEq for ConstKind<I> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Param(l0), Self::Param(r0)) => l0 == r0,
|
||||
(Self::Infer(l0), Self::Infer(r0)) => l0 == r0,
|
||||
(Self::Bound(l0, l1), Self::Bound(r0, r1)) => l0 == r0 && l1 == r1,
|
||||
(Self::Placeholder(l0), Self::Placeholder(r0)) => l0 == r0,
|
||||
(Self::Unevaluated(l0), Self::Unevaluated(r0)) => l0 == r0,
|
||||
(Self::Value(l0), Self::Value(r0)) => l0 == r0,
|
||||
(Self::Error(l0), Self::Error(r0)) => l0 == r0,
|
||||
(Self::Expr(l0), Self::Expr(r0)) => l0 == r0,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Eq for ConstKind<I> {}
|
||||
|
||||
impl<I: Interner> Clone for ConstKind<I> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Param(arg0) => Self::Param(arg0.clone()),
|
||||
Self::Infer(arg0) => Self::Infer(arg0.clone()),
|
||||
Self::Bound(arg0, arg1) => Self::Bound(arg0.clone(), arg1.clone()),
|
||||
Self::Placeholder(arg0) => Self::Placeholder(arg0.clone()),
|
||||
Self::Unevaluated(arg0) => Self::Unevaluated(arg0.clone()),
|
||||
Self::Value(arg0) => Self::Value(arg0.clone()),
|
||||
Self::Error(arg0) => Self::Error(arg0.clone()),
|
||||
Self::Expr(arg0) => Self::Expr(arg0.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of regions. Note that the NLL checker uses a distinct
|
||||
/// representation of regions. For this reason, it internally replaces all the
|
||||
/// regions with inference variables -- the index of the variable is then used
|
||||
|
|
|
@ -132,7 +132,12 @@ mod c_char_definition {
|
|||
),
|
||||
all(
|
||||
target_os = "netbsd",
|
||||
any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
|
||||
any(
|
||||
target_arch = "aarch64",
|
||||
target_arch = "arm",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "riscv64"
|
||||
)
|
||||
),
|
||||
all(
|
||||
target_os = "vxworks",
|
||||
|
|
|
@ -16,6 +16,8 @@ ignore = [
|
|||
"tests",
|
||||
|
||||
# do not format submodules
|
||||
# FIXME: sync submodule list with tidy/bootstrap/etc
|
||||
# tidy/src/walk.rs:filter_dirs
|
||||
"library/backtrace",
|
||||
"library/portable-simd",
|
||||
"library/stdarch",
|
||||
|
@ -31,10 +33,8 @@ ignore = [
|
|||
"src/tools/cargo",
|
||||
"src/tools/clippy",
|
||||
"src/tools/miri",
|
||||
"src/tools/rls",
|
||||
"src/tools/rust-analyzer",
|
||||
"src/tools/rustfmt",
|
||||
"src/tools/rust-installer",
|
||||
|
||||
# these are ignored by a standard cargo fmt run
|
||||
"compiler/rustc_codegen_cranelift/y.rs", # running rustfmt breaks this file
|
||||
|
|
|
@ -380,7 +380,10 @@ impl Step for Llvm {
|
|||
cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
|
||||
}
|
||||
|
||||
if target.starts_with("riscv") && !target.contains("freebsd") && !target.contains("openbsd")
|
||||
if target.starts_with("riscv")
|
||||
&& !target.contains("freebsd")
|
||||
&& !target.contains("openbsd")
|
||||
&& !target.contains("netbsd")
|
||||
{
|
||||
// RISC-V GCC erroneously requires linking against
|
||||
// `libatomic` when using 1-byte and 2-byte C++
|
||||
|
|
|
@ -289,7 +289,7 @@ bootstrap_tool!(
|
|||
Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = "test";
|
||||
BuildManifest, "src/tools/build-manifest", "build-manifest";
|
||||
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
|
||||
RustInstaller, "src/tools/rust-installer", "rust-installer", is_external_tool = true;
|
||||
RustInstaller, "src/tools/rust-installer", "rust-installer";
|
||||
RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
|
||||
ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
|
||||
LintDocs, "src/tools/lint-docs", "lint-docs";
|
||||
|
|
|
@ -305,6 +305,7 @@ target | std | host | notes
|
|||
`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD
|
||||
`riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia
|
||||
`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0)
|
||||
[`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ? | RISC-V NetBSD
|
||||
[`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
|
||||
`s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, MUSL)
|
||||
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
|
||||
|
|
|
@ -22,6 +22,7 @@ are currently defined running NetBSD:
|
|||
| `i686-unknown-netbsd` | [32-bit i386 with SSE](https://wiki.netbsd.org/ports/i386/) |
|
||||
| `mipsel-unknown-netbsd` | [32-bit mips, requires mips32 cpu support](https://wiki.netbsd.org/ports/evbmips/) |
|
||||
| `powerpc-unknown-netbsd` | [Various 32-bit PowerPC systems, e.g. MacPPC](https://wiki.netbsd.org/ports/macppc/) |
|
||||
| `riscv64gc-unknown-netbsd` | [64-bit RISC-V](https://wiki.netbsd.org/ports/riscv/)
|
||||
| `sparc64-unknown-netbsd` | [Sun UltraSPARC systems](https://wiki.netbsd.org/ports/sparc64/) |
|
||||
|
||||
All use the "native" `stdc++` library which goes along with the natively
|
||||
|
|
|
@ -689,7 +689,7 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t
|
|||
mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() {
|
||||
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||
ty::Array(sub_type, len) => match sub_type.kind() {
|
||||
ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(lcx.tcx) {
|
||||
ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) {
|
||||
Some(len) => alloc
|
||||
.inner()
|
||||
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
|
||||
|
@ -700,7 +700,7 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t
|
|||
.map(Constant::Vec),
|
||||
_ => None,
|
||||
},
|
||||
ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(lcx.tcx) {
|
||||
ty::Float(FloatTy::F64) => match len.try_to_target_usize(lcx.tcx) {
|
||||
Some(len) => alloc
|
||||
.inner()
|
||||
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap()))
|
||||
|
|
|
@ -468,7 +468,8 @@ uninstall_components() {
|
|||
verbose_msg "removing component manifest $_component_manifest"
|
||||
run rm "$_component_manifest"
|
||||
# This is a hard error because the installation is unrecoverable
|
||||
critical_need_ok "failed to remove installed manifest for component '$_installed_component'"
|
||||
local _err_cant_r_manifest="failed to remove installed manifest for component"
|
||||
critical_need_ok "$_err_cant_r_manifest '$_installed_component'"
|
||||
|
||||
# Update the installed component list
|
||||
local _modified_components="$(sed "/^$_installed_component\$/d" "$_md/components")"
|
||||
|
@ -692,7 +693,9 @@ maybe_configure_ld() {
|
|||
fi
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
warn "failed to run ldconfig. this may happen when not installing as root. run with --verbose to see the error"
|
||||
local _warn_s="failed to run ldconfig. this may happen when \
|
||||
not installing as root. run with --verbose to see the error"
|
||||
warn "$_warn_s"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
@ -977,7 +980,9 @@ make_dir_recursive "$abs_libdir/$TEMPLATE_REL_MANIFEST_DIR"
|
|||
need_ok "failed to create $TEMPLATE_REL_MANIFEST_DIR"
|
||||
|
||||
# Drop the version number into the manifest dir
|
||||
write_to_file "$TEMPLATE_RUST_INSTALLER_VERSION" "$abs_libdir/$TEMPLATE_REL_MANIFEST_DIR/rust-installer-version"
|
||||
write_to_file "$TEMPLATE_RUST_INSTALLER_VERSION" \
|
||||
"$abs_libdir/$TEMPLATE_REL_MANIFEST_DIR/rust-installer-version"
|
||||
|
||||
critical_need_ok "failed to write installer version"
|
||||
|
||||
# Install the uninstaller
|
||||
|
@ -992,5 +997,3 @@ maybe_configure_ld "$abs_libdir"
|
|||
echo
|
||||
echo " $TEMPLATE_SUCCESS_MESSAGE"
|
||||
echo
|
||||
|
||||
|
||||
|
|
|
@ -71,25 +71,16 @@ impl Combiner {
|
|||
|
||||
// Merge each installer into the work directory of the new installer.
|
||||
let components = create_new_file(package_dir.join("components"))?;
|
||||
for input_tarball in self
|
||||
.input_tarballs
|
||||
.split(',')
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
for input_tarball in self.input_tarballs.split(',').map(str::trim).filter(|s| !s.is_empty())
|
||||
{
|
||||
// Extract the input tarballs
|
||||
let compression =
|
||||
CompressionFormat::detect_from_path(input_tarball).ok_or_else(|| {
|
||||
anyhow::anyhow!("couldn't figure out the format of {}", input_tarball)
|
||||
})?;
|
||||
Archive::new(compression.decode(input_tarball)?)
|
||||
.unpack(&self.work_dir)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"unable to extract '{}' into '{}'",
|
||||
&input_tarball, self.work_dir
|
||||
)
|
||||
})?;
|
||||
Archive::new(compression.decode(input_tarball)?).unpack(&self.work_dir).with_context(
|
||||
|| format!("unable to extract '{}' into '{}'", &input_tarball, self.work_dir),
|
||||
)?;
|
||||
|
||||
let pkg_name =
|
||||
input_tarball.trim_end_matches(&format!(".tar.{}", compression.extension()));
|
||||
|
@ -126,11 +117,7 @@ impl Combiner {
|
|||
|
||||
// Write the installer version.
|
||||
let version = package_dir.join("rust-installer-version");
|
||||
writeln!(
|
||||
create_new_file(version)?,
|
||||
"{}",
|
||||
crate::RUST_INSTALLER_VERSION
|
||||
)
|
||||
writeln!(create_new_file(version)?, "{}", crate::RUST_INSTALLER_VERSION)
|
||||
.context("failed to write new installer version")?;
|
||||
|
||||
// Copy the overlay.
|
||||
|
|
|
@ -86,11 +86,7 @@ impl Generator {
|
|||
|
||||
// Write the installer version (only used by combine-installers.sh)
|
||||
let version = package_dir.join("rust-installer-version");
|
||||
writeln!(
|
||||
create_new_file(version)?,
|
||||
"{}",
|
||||
crate::RUST_INSTALLER_VERSION
|
||||
)
|
||||
writeln!(create_new_file(version)?, "{}", crate::RUST_INSTALLER_VERSION)
|
||||
.context("failed to write new installer version")?;
|
||||
|
||||
// Copy the overlay
|
||||
|
@ -128,33 +124,19 @@ impl Generator {
|
|||
/// Copies the `src` directory recursively to `dst`, writing `manifest.in` too.
|
||||
fn copy_and_manifest(src: &Path, dst: &Path, bulk_dirs: &str) -> Result<()> {
|
||||
let mut manifest = create_new_file(dst.join("manifest.in"))?;
|
||||
let bulk_dirs: Vec<_> = bulk_dirs
|
||||
.split(',')
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(Path::new)
|
||||
.collect();
|
||||
let bulk_dirs: Vec<_> = bulk_dirs.split(',').filter(|s| !s.is_empty()).map(Path::new).collect();
|
||||
|
||||
let mut paths = BTreeSet::new();
|
||||
copy_with_callback(src, dst, |path, file_type| {
|
||||
// We need paths to be compatible with both Unix and Windows.
|
||||
if path
|
||||
.components()
|
||||
.filter_map(|c| c.as_os_str().to_str())
|
||||
.any(|s| s.contains('\\'))
|
||||
{
|
||||
bail!(
|
||||
"rust-installer doesn't support '\\' in path components: {:?}",
|
||||
path
|
||||
);
|
||||
if path.components().filter_map(|c| c.as_os_str().to_str()).any(|s| s.contains('\\')) {
|
||||
bail!("rust-installer doesn't support '\\' in path components: {:?}", path);
|
||||
}
|
||||
|
||||
// Normalize to Unix-style path separators.
|
||||
let normalized_string;
|
||||
let mut string = path.to_str().ok_or_else(|| {
|
||||
format_err!(
|
||||
"rust-installer doesn't support non-Unicode paths: {:?}",
|
||||
path
|
||||
)
|
||||
format_err!("rust-installer doesn't support non-Unicode paths: {:?}", path)
|
||||
})?;
|
||||
if string.contains('\\') {
|
||||
normalized_string = string.replace('\\', "/");
|
||||
|
|
|
@ -19,8 +19,12 @@ fn main() -> Result<()> {
|
|||
let command_line = CommandLine::parse();
|
||||
match command_line.command {
|
||||
Subcommand::Combine(combiner) => combiner.run().context("failed to combine installers")?,
|
||||
Subcommand::Generate(generator) => generator.run().context("failed to generate installer")?,
|
||||
Subcommand::Script(scripter) => scripter.run().context("failed to generate installation script")?,
|
||||
Subcommand::Generate(generator) => {
|
||||
generator.run().context("failed to generate installer")?
|
||||
}
|
||||
Subcommand::Script(scripter) => {
|
||||
scripter.run().context("failed to generate installation script")?
|
||||
}
|
||||
Subcommand::Tarball(tarballer) => tarballer.run().context("failed to generate tarballs")?,
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -32,22 +32,19 @@ actor! {
|
|||
impl Scripter {
|
||||
/// Generates the actual installer script
|
||||
pub fn run(self) -> Result<()> {
|
||||
// Replace dashes in the success message with spaces (our arg handling botches spaces)
|
||||
// TODO: still needed? Kept for compatibility for now.
|
||||
// Replace dashes in the product name with spaces (our arg handling botches spaces)
|
||||
// FIXME: still needed? Kept for compatibility for now.
|
||||
let product_name = self.product_name.replace('-', " ");
|
||||
|
||||
// Replace dashes in the success message with spaces (our arg handling botches spaces)
|
||||
// TODO: still needed? Kept for compatibility for now.
|
||||
// FIXME: still needed? Kept for compatibility for now.
|
||||
let success_message = self.success_message.replace('-', " ");
|
||||
|
||||
let script = TEMPLATE
|
||||
.replace("%%TEMPLATE_PRODUCT_NAME%%", &sh_quote(&product_name))
|
||||
.replace("%%TEMPLATE_REL_MANIFEST_DIR%%", &self.rel_manifest_dir)
|
||||
.replace("%%TEMPLATE_SUCCESS_MESSAGE%%", &sh_quote(&success_message))
|
||||
.replace(
|
||||
"%%TEMPLATE_LEGACY_MANIFEST_DIRS%%",
|
||||
&sh_quote(&self.legacy_manifest_dirs),
|
||||
)
|
||||
.replace("%%TEMPLATE_LEGACY_MANIFEST_DIRS%%", &sh_quote(&self.legacy_manifest_dirs))
|
||||
.replace(
|
||||
"%%TEMPLATE_RUST_INSTALLER_VERSION%%",
|
||||
&sh_quote(&crate::RUST_INSTALLER_VERSION),
|
||||
|
|
|
@ -58,10 +58,7 @@ impl Tarballer {
|
|||
let buf = BufWriter::with_capacity(1024 * 1024, encoder);
|
||||
let mut builder = Builder::new(buf);
|
||||
|
||||
let pool = rayon::ThreadPoolBuilder::new()
|
||||
.num_threads(2)
|
||||
.build()
|
||||
.unwrap();
|
||||
let pool = rayon::ThreadPoolBuilder::new().num_threads(2).build().unwrap();
|
||||
pool.install(move || {
|
||||
for path in dirs {
|
||||
let src = Path::new(&self.work_dir).join(&path);
|
||||
|
@ -122,11 +119,7 @@ where
|
|||
let name = name.as_ref();
|
||||
|
||||
if !name.is_relative() && !name.starts_with(root) {
|
||||
bail!(
|
||||
"input '{}' is not in work dir '{}'",
|
||||
name.display(),
|
||||
root.display()
|
||||
);
|
||||
bail!("input '{}' is not in work dir '{}'", name.display(), root.display());
|
||||
}
|
||||
|
||||
let mut dirs = vec![];
|
||||
|
|
|
@ -15,8 +15,7 @@ use std::os::windows::fs::symlink_file;
|
|||
|
||||
/// Converts a `&Path` to a UTF-8 `&str`.
|
||||
pub fn path_to_str(path: &Path) -> Result<&str> {
|
||||
path.to_str()
|
||||
.ok_or_else(|| format_err!("path is not valid UTF-8 '{}'", path.display()))
|
||||
path.to_str().ok_or_else(|| format_err!("path is not valid UTF-8 '{}'", path.display()))
|
||||
}
|
||||
|
||||
/// Wraps `fs::copy` with a nicer error message.
|
||||
|
@ -27,11 +26,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<u64> {
|
|||
Ok(0)
|
||||
} else {
|
||||
let amt = fs::copy(&from, &to).with_context(|| {
|
||||
format!(
|
||||
"failed to copy '{}' to '{}'",
|
||||
from.as_ref().display(),
|
||||
to.as_ref().display()
|
||||
)
|
||||
format!("failed to copy '{}' to '{}'", from.as_ref().display(), to.as_ref().display())
|
||||
})?;
|
||||
Ok(amt)
|
||||
}
|
||||
|
@ -123,8 +118,12 @@ where
|
|||
}
|
||||
|
||||
macro_rules! actor_field_default {
|
||||
() => { Default::default() };
|
||||
(= $expr:expr) => { $expr.into() }
|
||||
() => {
|
||||
Default::default()
|
||||
};
|
||||
(= $expr:expr) => {
|
||||
$expr.into()
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates an "actor" with default values, setters for all fields, and Clap parser support.
|
||||
|
|
|
@ -458,7 +458,8 @@ uninstall_from_installed_script_with_args_fails() {
|
|||
--output-dir="$OUT_DIR/c1" \
|
||||
--component-name=rustc
|
||||
try "$WORK_DIR/c1/package/install.sh" --prefix="$PREFIX_DIR"
|
||||
expect_output_fail "uninstall.sh does not take any arguments" sh "$PREFIX_DIR/lib/packagelib/uninstall.sh" --prefix=foo
|
||||
expect_output_fail "uninstall.sh does not take any arguments" \
|
||||
sh "$PREFIX_DIR/lib/packagelib/uninstall.sh" --prefix=foo
|
||||
}
|
||||
runtest uninstall_from_installed_script_with_args_fails
|
||||
|
||||
|
@ -680,7 +681,8 @@ select_components_to_install() {
|
|||
try test -e "$PREFIX_DIR/bin/program"
|
||||
try test -e "$PREFIX_DIR/bin/cargo"
|
||||
try test ! -e "$PREFIX_DIR/baz"
|
||||
try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" --components=rustc,cargo,rust-docs
|
||||
try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" \
|
||||
--components=rustc,cargo,rust-docs
|
||||
try test ! -e "$PREFIX_DIR/bin/program"
|
||||
try test ! -e "$PREFIX_DIR/bin/cargo"
|
||||
try test ! -e "$PREFIX_DIR/baz"
|
||||
|
@ -733,7 +735,8 @@ select_components_to_uninstall() {
|
|||
try test ! -e "$PREFIX_DIR/bin/cargo"
|
||||
try test -e "$PREFIX_DIR/baz"
|
||||
try "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR"
|
||||
try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" --components=rustc,cargo,rust-docs
|
||||
try "$WORK_DIR/rust/install.sh --uninstall" --prefix="$PREFIX_DIR" \
|
||||
--components=rustc,cargo,rust-docs
|
||||
try test ! -e "$PREFIX_DIR/bin/program"
|
||||
try test ! -e "$PREFIX_DIR/bin/cargo"
|
||||
try test ! -e "$PREFIX_DIR/baz"
|
||||
|
@ -765,7 +768,8 @@ invalid_component() {
|
|||
--output-dir="$OUT_DIR" \
|
||||
--package-name=rust \
|
||||
--input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz"
|
||||
expect_output_fail "unknown component" "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" --components=foo
|
||||
expect_output_fail "unknown component" "$WORK_DIR/rust/install.sh" --prefix="$PREFIX_DIR" \
|
||||
--components=foo
|
||||
}
|
||||
runtest invalid_component
|
||||
|
||||
|
|
|
@ -95,17 +95,41 @@ mod os_impl {
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME: check when rust-installer test sh files will be removed,
|
||||
// and then remove them from exclude list
|
||||
const RI_EXCLUSION_LIST: &[&str] = &[
|
||||
"src/tools/rust-installer/test/image1/bin/program",
|
||||
"src/tools/rust-installer/test/image1/bin/program2",
|
||||
"src/tools/rust-installer/test/image1/bin/bad-bin",
|
||||
"src/tools/rust-installer/test/image2/bin/oldprogram",
|
||||
"src/tools/rust-installer/test/image3/bin/cargo",
|
||||
];
|
||||
|
||||
fn filter_rust_installer_no_so_bins(path: &Path) -> bool {
|
||||
RI_EXCLUSION_LIST.iter().any(|p| path.ends_with(p))
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
use std::ffi::OsStr;
|
||||
|
||||
const ALLOWED: &[&str] = &["configure", "x"];
|
||||
|
||||
for p in RI_EXCLUSION_LIST {
|
||||
if !path.join(Path::new(p)).exists() {
|
||||
tidy_error!(bad, "rust-installer test bins missed: {p}");
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: we don't need to look at all binaries, only files that have been modified in this branch
|
||||
// (e.g. using `git ls-files`).
|
||||
walk_no_read(
|
||||
&[path],
|
||||
|path, _is_dir| filter_dirs(path) || path.ends_with("src/etc"),
|
||||
|path, _is_dir| {
|
||||
filter_dirs(path)
|
||||
|| path.ends_with("src/etc")
|
||||
|| filter_rust_installer_no_so_bins(path)
|
||||
},
|
||||
&mut |entry| {
|
||||
let file = entry.path();
|
||||
let extension = file.extension();
|
||||
|
|
|
@ -4,6 +4,8 @@ use std::{ffi::OsStr, fs::File, io::Read, path::Path};
|
|||
|
||||
/// The default directory filter.
|
||||
pub fn filter_dirs(path: &Path) -> bool {
|
||||
// FIXME: sync submodule exclusion list with rustfmt.toml
|
||||
// bootstrap/etc
|
||||
let skip = [
|
||||
"tidy-test-file",
|
||||
"compiler/rustc_codegen_cranelift",
|
||||
|
@ -15,9 +17,7 @@ pub fn filter_dirs(path: &Path) -> bool {
|
|||
"src/tools/cargo",
|
||||
"src/tools/clippy",
|
||||
"src/tools/miri",
|
||||
"src/tools/rls",
|
||||
"src/tools/rust-analyzer",
|
||||
"src/tools/rust-installer",
|
||||
"src/tools/rustfmt",
|
||||
"src/doc/book",
|
||||
"src/doc/edition-guide",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
| User Type Annotations
|
||||
| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
|
||||
| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated([], DefId(0:8 ~ issue_99325[22bb]::main::{constant#1})) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
|
||||
| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), substs: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
|
||||
|
|
||||
fn main() -> () {
|
||||
let mut _0: ();
|
||||
|
|
|
@ -24,5 +24,6 @@ fn main() {
|
|||
type F = impl Future;
|
||||
// Check that statics are inhabited computes they layout.
|
||||
static POOL: Task<F> = Task::new();
|
||||
//~^ ERROR: cannot check whether the hidden type of `layout_error[b009]::main::F::{opaque#0}` satisfies auto traits
|
||||
Task::spawn(&POOL, || cb());
|
||||
}
|
||||
|
|
|
@ -4,6 +4,24 @@ error[E0425]: cannot find value `Foo` in this scope
|
|||
LL | let a = Foo;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error: aborting due to previous error
|
||||
error: cannot check whether the hidden type of `layout_error[b009]::main::F::{opaque#0}` satisfies auto traits
|
||||
--> $DIR/layout-error.rs:26:18
|
||||
|
|
||||
LL | static POOL: Task<F> = Task::new();
|
||||
| ^^^^^^^
|
||||
|
|
||||
note: opaque type is declared here
|
||||
--> $DIR/layout-error.rs:24:14
|
||||
|
|
||||
LL | type F = impl Future;
|
||||
| ^^^^^^^^^^^
|
||||
note: required because it appears within the type `Task<F>`
|
||||
--> $DIR/layout-error.rs:9:12
|
||||
|
|
||||
LL | pub struct Task<F: Future>(F);
|
||||
| ^^^^
|
||||
= note: shared static variables must have a type that implements `Sync`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0425`.
|
||||
|
|
|
@ -3,21 +3,23 @@ use std::rc::Rc;
|
|||
|
||||
fn send<T: Send>(_: T) {}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
fn main() {}
|
||||
|
||||
// Cycles should work as the deferred obligations are
|
||||
// independently resolved and only require the concrete
|
||||
// return type, which can't depend on the obligation.
|
||||
fn cycle1() -> impl Clone {
|
||||
//~^ ERROR cycle detected
|
||||
//~| ERROR cycle detected
|
||||
send(cycle2().clone());
|
||||
//~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits
|
||||
|
||||
Rc::new(Cell::new(5))
|
||||
}
|
||||
|
||||
fn cycle2() -> impl Clone {
|
||||
send(cycle1().clone());
|
||||
//~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits
|
||||
|
||||
Rc::new(String::from("foo"))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}`
|
||||
--> $DIR/auto-trait-leak.rs:12:16
|
||||
--> $DIR/auto-trait-leak.rs:11:16
|
||||
|
|
||||
LL | fn cycle1() -> impl Clone {
|
||||
| ^^^^^^^^^^
|
||||
|
@ -11,12 +11,12 @@ LL | send(cycle2().clone());
|
|||
| ^^^^
|
||||
= note: ...which requires evaluating trait selection obligation `cycle2::{opaque#0}: core::marker::Send`...
|
||||
note: ...which requires computing type of `cycle2::{opaque#0}`...
|
||||
--> $DIR/auto-trait-leak.rs:19:16
|
||||
--> $DIR/auto-trait-leak.rs:20:16
|
||||
|
|
||||
LL | fn cycle2() -> impl Clone {
|
||||
| ^^^^^^^^^^
|
||||
note: ...which requires type-checking `cycle2`...
|
||||
--> $DIR/auto-trait-leak.rs:20:5
|
||||
--> $DIR/auto-trait-leak.rs:21:5
|
||||
|
|
||||
LL | send(cycle1().clone());
|
||||
| ^^^^
|
||||
|
@ -34,6 +34,89 @@ LL | | Rc::new(String::from("foo"))
|
|||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}`
|
||||
--> $DIR/auto-trait-leak.rs:11:16
|
||||
|
|
||||
LL | fn cycle1() -> impl Clone {
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires type-checking `cycle1`...
|
||||
--> $DIR/auto-trait-leak.rs:14:5
|
||||
|
|
||||
LL | send(cycle2().clone());
|
||||
| ^^^^
|
||||
= note: ...which requires evaluating trait selection obligation `cycle2::{opaque#0}: core::marker::Send`...
|
||||
note: ...which requires computing type of `cycle2::{opaque#0}`...
|
||||
--> $DIR/auto-trait-leak.rs:20:16
|
||||
|
|
||||
LL | fn cycle2() -> impl Clone {
|
||||
| ^^^^^^^^^^
|
||||
note: ...which requires type-checking `cycle2`...
|
||||
--> $DIR/auto-trait-leak.rs:20:1
|
||||
|
|
||||
LL | fn cycle2() -> impl Clone {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
|
||||
note: cycle used when checking item types in top-level module
|
||||
--> $DIR/auto-trait-leak.rs:1:1
|
||||
|
|
||||
LL | / use std::cell::Cell;
|
||||
LL | | use std::rc::Rc;
|
||||
LL | |
|
||||
LL | | fn send<T: Send>(_: T) {}
|
||||
... |
|
||||
LL | | Rc::new(String::from("foo"))
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: cannot check whether the hidden type of opaque type satisfies auto traits
|
||||
--> $DIR/auto-trait-leak.rs:21:10
|
||||
|
|
||||
LL | send(cycle1().clone());
|
||||
| ---- ^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: opaque type is declared here
|
||||
--> $DIR/auto-trait-leak.rs:11:16
|
||||
|
|
||||
LL | fn cycle1() -> impl Clone {
|
||||
| ^^^^^^^^^^
|
||||
note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
|
||||
--> $DIR/auto-trait-leak.rs:20:4
|
||||
|
|
||||
LL | fn cycle2() -> impl Clone {
|
||||
| ^^^^^^
|
||||
note: required by a bound in `send`
|
||||
--> $DIR/auto-trait-leak.rs:4:12
|
||||
|
|
||||
LL | fn send<T: Send>(_: T) {}
|
||||
| ^^^^ required by this bound in `send`
|
||||
|
||||
error: cannot check whether the hidden type of opaque type satisfies auto traits
|
||||
--> $DIR/auto-trait-leak.rs:14:10
|
||||
|
|
||||
LL | send(cycle2().clone());
|
||||
| ---- ^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: opaque type is declared here
|
||||
--> $DIR/auto-trait-leak.rs:20:16
|
||||
|
|
||||
LL | fn cycle2() -> impl Clone {
|
||||
| ^^^^^^^^^^
|
||||
note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
|
||||
--> $DIR/auto-trait-leak.rs:11:4
|
||||
|
|
||||
LL | fn cycle1() -> impl Clone {
|
||||
| ^^^^^^
|
||||
note: required by a bound in `send`
|
||||
--> $DIR/auto-trait-leak.rs:4:12
|
||||
|
|
||||
LL | fn send<T: Send>(_: T) {}
|
||||
| ^^^^ required by this bound in `send`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0391`.
|
||||
|
|
|
@ -24,6 +24,8 @@ where
|
|||
B: Send, // <- a second bound
|
||||
{
|
||||
normalize(broken_fut(), ());
|
||||
//~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits
|
||||
//~| ERROR: cannot check whether the hidden type of opaque type satisfies auto traits
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -4,6 +4,61 @@ error[E0425]: cannot find value `ident_error` in this scope
|
|||
LL | ident_error;
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error: aborting due to previous error
|
||||
error: cannot check whether the hidden type of opaque type satisfies auto traits
|
||||
--> $DIR/issue-103181-2.rs:26:15
|
||||
|
|
||||
LL | normalize(broken_fut(), ());
|
||||
| --------- ^^^^^^^^^^^^
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: opaque type is declared here
|
||||
--> $DIR/issue-103181-2.rs:11:23
|
||||
|
|
||||
LL | async fn broken_fut() {
|
||||
| ^
|
||||
note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
|
||||
--> $DIR/issue-103181-2.rs:20:10
|
||||
|
|
||||
LL | async fn iceice<A, B>()
|
||||
| ^^^^^^
|
||||
note: required for `impl Future<Output = ()>` to implement `SendFuture`
|
||||
--> $DIR/issue-103181-2.rs:7:17
|
||||
|
|
||||
LL | impl<Fut: Send> SendFuture for Fut {
|
||||
| ---- ^^^^^^^^^^ ^^^
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
note: required by a bound in `normalize`
|
||||
--> $DIR/issue-103181-2.rs:18:19
|
||||
|
|
||||
LL | fn normalize<Fut: SendFuture>(_: Fut, _: Fut::Output) {}
|
||||
| ^^^^^^^^^^ required by this bound in `normalize`
|
||||
|
||||
error: cannot check whether the hidden type of opaque type satisfies auto traits
|
||||
--> $DIR/issue-103181-2.rs:26:5
|
||||
|
|
||||
LL | normalize(broken_fut(), ());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: opaque type is declared here
|
||||
--> $DIR/issue-103181-2.rs:11:23
|
||||
|
|
||||
LL | async fn broken_fut() {
|
||||
| ^
|
||||
note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
|
||||
--> $DIR/issue-103181-2.rs:20:10
|
||||
|
|
||||
LL | async fn iceice<A, B>()
|
||||
| ^^^^^^
|
||||
note: required for `impl Future<Output = ()>` to implement `SendFuture`
|
||||
--> $DIR/issue-103181-2.rs:7:17
|
||||
|
|
||||
LL | impl<Fut: Send> SendFuture for Fut {
|
||||
| ---- ^^^^^^^^^^ ^^^
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0425`.
|
||||
|
|
22
tests/ui/traits/new-solver/winnow-specializing-impls.rs
Normal file
22
tests/ui/traits/new-solver/winnow-specializing-impls.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// build-pass
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
|
||||
// Tests that the specializing impl `<() as Foo>` holds during codegen.
|
||||
|
||||
#![feature(min_specialization)]
|
||||
|
||||
trait Foo {
|
||||
fn bar();
|
||||
}
|
||||
|
||||
impl<T> Foo for T {
|
||||
default fn bar() {}
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
fn bar() {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
<() as Foo>::bar();
|
||||
}
|
|
@ -4,8 +4,9 @@
|
|||
// FIXME This should compile, but it currently doesn't
|
||||
|
||||
mod m {
|
||||
type Foo = impl std::fmt::Debug;
|
||||
pub type Foo = impl std::fmt::Debug;
|
||||
//~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391]
|
||||
//~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391]
|
||||
|
||||
pub fn foo() -> Foo {
|
||||
22_u32
|
||||
|
@ -13,6 +14,7 @@ mod m {
|
|||
|
||||
pub fn bar() {
|
||||
is_send(foo());
|
||||
//~^ ERROR: cannot check whether the hidden type of `auto_trait_leakage3[211d]::m::Foo::{opaque#0}
|
||||
}
|
||||
|
||||
fn is_send<T: Send>(_: T) {}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}`
|
||||
--> $DIR/auto-trait-leakage3.rs:7:16
|
||||
--> $DIR/auto-trait-leakage3.rs:7:20
|
||||
|
|
||||
LL | type Foo = impl std::fmt::Debug;
|
||||
LL | pub type Foo = impl std::fmt::Debug;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires type-checking `m::bar`...
|
||||
--> $DIR/auto-trait-leakage3.rs:15:9
|
||||
--> $DIR/auto-trait-leakage3.rs:16:9
|
||||
|
|
||||
LL | is_send(foo());
|
||||
| ^^^^^^^
|
||||
|
@ -17,6 +17,48 @@ note: cycle used when checking item types in module `m`
|
|||
LL | mod m {
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}`
|
||||
--> $DIR/auto-trait-leakage3.rs:7:20
|
||||
|
|
||||
LL | pub type Foo = impl std::fmt::Debug;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires type-checking `m::bar`...
|
||||
--> $DIR/auto-trait-leakage3.rs:15:5
|
||||
|
|
||||
LL | pub fn bar() {
|
||||
| ^^^^^^^^^^^^
|
||||
= note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
|
||||
note: cycle used when checking item types in module `m`
|
||||
--> $DIR/auto-trait-leakage3.rs:6:1
|
||||
|
|
||||
LL | mod m {
|
||||
| ^^^^^
|
||||
|
||||
error: cannot check whether the hidden type of `auto_trait_leakage3[211d]::m::Foo::{opaque#0}` satisfies auto traits
|
||||
--> $DIR/auto-trait-leakage3.rs:16:17
|
||||
|
|
||||
LL | is_send(foo());
|
||||
| ------- ^^^^^
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: opaque type is declared here
|
||||
--> $DIR/auto-trait-leakage3.rs:7:20
|
||||
|
|
||||
LL | pub type Foo = impl std::fmt::Debug;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
|
||||
--> $DIR/auto-trait-leakage3.rs:15:12
|
||||
|
|
||||
LL | pub fn bar() {
|
||||
| ^^^
|
||||
note: required by a bound in `is_send`
|
||||
--> $DIR/auto-trait-leakage3.rs:20:19
|
||||
|
|
||||
LL | fn is_send<T: Send>(_: T) {}
|
||||
| ^^^^ required by this bound in `is_send`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0391`.
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
mod m {
|
||||
type Foo = impl std::fmt::Debug;
|
||||
pub type Foo = impl std::fmt::Debug;
|
||||
//~^ ERROR cycle detected
|
||||
//~| ERROR cycle detected
|
||||
|
||||
// Cycle: error today, but it'd be nice if it eventually worked
|
||||
|
||||
|
@ -13,10 +14,11 @@ mod m {
|
|||
|
||||
pub fn bar() {
|
||||
is_send(foo()); // Today: error
|
||||
//~^ ERROR: cannot check whether the hidden type of `inference_cycle[4ecc]::m::Foo::{opaque#0}` satisfies auto traits
|
||||
}
|
||||
|
||||
fn baz() {
|
||||
let f: Foo = 22_u32;
|
||||
let f: Foo = ();
|
||||
}
|
||||
|
||||
fn is_send<T: Send>(_: T) {}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}`
|
||||
--> $DIR/inference-cycle.rs:5:16
|
||||
--> $DIR/inference-cycle.rs:5:20
|
||||
|
|
||||
LL | type Foo = impl std::fmt::Debug;
|
||||
LL | pub type Foo = impl std::fmt::Debug;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires type-checking `m::bar`...
|
||||
--> $DIR/inference-cycle.rs:15:9
|
||||
--> $DIR/inference-cycle.rs:16:9
|
||||
|
|
||||
LL | is_send(foo()); // Today: error
|
||||
| ^^^^^^^
|
||||
|
@ -17,6 +17,48 @@ note: cycle used when checking item types in module `m`
|
|||
LL | mod m {
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}`
|
||||
--> $DIR/inference-cycle.rs:5:20
|
||||
|
|
||||
LL | pub type Foo = impl std::fmt::Debug;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires type-checking `m::bar`...
|
||||
--> $DIR/inference-cycle.rs:15:5
|
||||
|
|
||||
LL | pub fn bar() {
|
||||
| ^^^^^^^^^^^^
|
||||
= note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
|
||||
note: cycle used when checking item types in module `m`
|
||||
--> $DIR/inference-cycle.rs:4:1
|
||||
|
|
||||
LL | mod m {
|
||||
| ^^^^^
|
||||
|
||||
error: cannot check whether the hidden type of `inference_cycle[4ecc]::m::Foo::{opaque#0}` satisfies auto traits
|
||||
--> $DIR/inference-cycle.rs:16:17
|
||||
|
|
||||
LL | is_send(foo()); // Today: error
|
||||
| ------- ^^^^^
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: opaque type is declared here
|
||||
--> $DIR/inference-cycle.rs:5:20
|
||||
|
|
||||
LL | pub type Foo = impl std::fmt::Debug;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
|
||||
--> $DIR/inference-cycle.rs:15:12
|
||||
|
|
||||
LL | pub fn bar() {
|
||||
| ^^^
|
||||
note: required by a bound in `is_send`
|
||||
--> $DIR/inference-cycle.rs:24:19
|
||||
|
|
||||
LL | fn is_send<T: Send>(_: T) {}
|
||||
| ^^^^ required by this bound in `is_send`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0391`.
|
||||
|
|
|
@ -4,13 +4,16 @@ use std::fmt::Debug;
|
|||
|
||||
type Foo = impl Debug;
|
||||
//~^ ERROR cycle detected
|
||||
//~| ERROR cycle detected
|
||||
//~| ERROR cycle detected
|
||||
|
||||
fn is_send<T: Send>() { }
|
||||
fn is_send<T: Send>() {}
|
||||
|
||||
fn not_good() {
|
||||
// Error: this function does not constrain `Foo` to any particular
|
||||
// hidden type, so it cannot rely on `Send` being true.
|
||||
is_send::<Foo>();
|
||||
//~^ ERROR: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits
|
||||
}
|
||||
|
||||
fn not_gooder() {
|
||||
|
@ -20,6 +23,7 @@ fn not_gooder() {
|
|||
// while we could know this from the hidden type, it would
|
||||
// need extra roundabout logic to support it.
|
||||
is_send::<Foo>();
|
||||
//~^ ERROR: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -5,7 +5,7 @@ LL | type Foo = impl Debug;
|
|||
| ^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires type-checking `not_good`...
|
||||
--> $DIR/reveal_local.rs:13:5
|
||||
--> $DIR/reveal_local.rs:15:5
|
||||
|
|
||||
LL | is_send::<Foo>();
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -23,6 +23,98 @@ LL | |
|
|||
LL | | fn main() {}
|
||||
| |____________^
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
|
||||
--> $DIR/reveal_local.rs:5:12
|
||||
|
|
||||
LL | type Foo = impl Debug;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires type-checking `not_good`...
|
||||
--> $DIR/reveal_local.rs:12:1
|
||||
|
|
||||
LL | fn not_good() {
|
||||
| ^^^^^^^^^^^^^
|
||||
= note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
|
||||
note: cycle used when checking item types in top-level module
|
||||
--> $DIR/reveal_local.rs:1:1
|
||||
|
|
||||
LL | / #![feature(type_alias_impl_trait)]
|
||||
LL | |
|
||||
LL | | use std::fmt::Debug;
|
||||
LL | |
|
||||
... |
|
||||
LL | |
|
||||
LL | | fn main() {}
|
||||
| |____________^
|
||||
|
||||
error: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits
|
||||
--> $DIR/reveal_local.rs:15:15
|
||||
|
|
||||
LL | is_send::<Foo>();
|
||||
| ^^^
|
||||
|
|
||||
note: opaque type is declared here
|
||||
--> $DIR/reveal_local.rs:5:12
|
||||
|
|
||||
LL | type Foo = impl Debug;
|
||||
| ^^^^^^^^^^
|
||||
note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
|
||||
--> $DIR/reveal_local.rs:12:4
|
||||
|
|
||||
LL | fn not_good() {
|
||||
| ^^^^^^^^
|
||||
note: required by a bound in `is_send`
|
||||
--> $DIR/reveal_local.rs:10:15
|
||||
|
|
||||
LL | fn is_send<T: Send>() {}
|
||||
| ^^^^ required by this bound in `is_send`
|
||||
|
||||
error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
|
||||
--> $DIR/reveal_local.rs:5:12
|
||||
|
|
||||
LL | type Foo = impl Debug;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires type-checking `not_gooder`...
|
||||
--> $DIR/reveal_local.rs:19:1
|
||||
|
|
||||
LL | fn not_gooder() {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
= note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
|
||||
note: cycle used when checking item types in top-level module
|
||||
--> $DIR/reveal_local.rs:1:1
|
||||
|
|
||||
LL | / #![feature(type_alias_impl_trait)]
|
||||
LL | |
|
||||
LL | | use std::fmt::Debug;
|
||||
LL | |
|
||||
... |
|
||||
LL | |
|
||||
LL | | fn main() {}
|
||||
| |____________^
|
||||
|
||||
error: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits
|
||||
--> $DIR/reveal_local.rs:25:15
|
||||
|
|
||||
LL | is_send::<Foo>();
|
||||
| ^^^
|
||||
|
|
||||
note: opaque type is declared here
|
||||
--> $DIR/reveal_local.rs:5:12
|
||||
|
|
||||
LL | type Foo = impl Debug;
|
||||
| ^^^^^^^^^^
|
||||
note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
|
||||
--> $DIR/reveal_local.rs:19:4
|
||||
|
|
||||
LL | fn not_gooder() {
|
||||
| ^^^^^^^^^^
|
||||
note: required by a bound in `is_send`
|
||||
--> $DIR/reveal_local.rs:10:15
|
||||
|
|
||||
LL | fn is_send<T: Send>() {}
|
||||
| ^^^^ required by this bound in `is_send`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0391`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue