diff options
316 files changed, 3922 insertions, 2493 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a59c83de0f4..edc1e2f0b84 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1308,7 +1308,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync { match a { - Async::Yes { .. } => hir::IsAsync::Async, + Async::Yes { span, .. } => hir::IsAsync::Async(span), Async::No => hir::IsAsync::NotAsync, } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 099e07e8841..f70263e9dcf 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,7 +13,7 @@ use rustc_index::IndexSlice; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, + AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; @@ -101,12 +101,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let terminator = self.body[location.block].terminator(); debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator); if let TerminatorKind::Call { - func: Operand::Constant(box Constant { literal, .. }), + func: Operand::Constant(box ConstOperand { const_, .. }), args, .. } = &terminator.kind { - if let ty::FnDef(id, _) = *literal.ty().kind() { + if let ty::FnDef(id, _) = *const_.ty().kind() { debug!("add_moved_or_invoked_closure_note: id={:?}", id); if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() { let closure = match args.first() { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index b40e89e471d..096bf826cfb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -302,7 +302,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { if free_region.bound_region.is_named() { // A named region that is actually named. Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) }) - } else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) { + } else if tcx.asyncness(self.mir_hir_id().owner).is_async() { // If we spuriously thought that the region is named, we should let the // system generate a true name for error messages. Currently this can // happen if we have an elided name in an async fn for example: the diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 4c69ea843c7..4c7c4982050 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -4,8 +4,7 @@ use crate::BorrowckInferCtxt; use rustc_index::IndexSlice; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::visit::{MutVisitor, TyContext}; -use rustc_middle::mir::Constant; -use rustc_middle::mir::{Body, Location, Promoted}; +use rustc_middle::mir::{Body, ConstOperand, Location, Promoted}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::{Span, Symbol}; @@ -117,9 +116,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) { - let literal = constant.literal; - constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location)); + fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { + let const_ = constant.const_; + constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location)); debug!("constant: {:#?}", constant); } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 0f661421cdc..60e6dcaf0b8 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -302,11 +302,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { self.sanitize_place(place, location, context); } - fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { debug!(?constant, ?location, "visit_constant"); self.super_constant(constant, location); - let ty = self.sanitize_type(constant, constant.literal.ty()); + let ty = self.sanitize_type(constant, constant.const_.ty()); self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { let live_region_vid = @@ -328,7 +328,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( - constant.literal.ty(), + constant.const_.ty(), ty::Variance::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, locations, @@ -340,20 +340,20 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { constant, "bad constant user type {:?} vs {:?}: {:?}", annotation, - constant.literal.ty(), + constant.const_.ty(), terr, ); } } else { let tcx = self.tcx(); - let maybe_uneval = match constant.literal { - ConstantKind::Ty(ct) => match ct.kind() { + let maybe_uneval = match constant.const_ { + Const::Ty(ct) => match ct.kind() { ty::ConstKind::Unevaluated(_) => { - bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct) + bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct) } _ => None, }, - ConstantKind::Unevaluated(uv, _) => Some(uv), + Const::Unevaluated(uv, _) => Some(uv), _ => None, }; @@ -384,7 +384,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { check_err(self, promoted_body, ty, promoted_ty); } else { self.cx.ascribe_user_type( - constant.literal.ty(), + constant.const_.ty(), UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }), locations.span(&self.cx.body), ); @@ -392,7 +392,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); let normalized_ty = self.cx.normalize(unnormalized_ty, locations); - let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty; + let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty; if let Err(terr) = self.cx.eq_types( literal_ty, @@ -404,7 +404,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } } - if let ty::FnDef(def_id, args) = *constant.literal.ty().kind() { + if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args); self.cx.normalize_and_prove_instantiated_predicates( def_id, @@ -1801,9 +1801,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!(?op, ?location, "check_operand"); if let Operand::Constant(constant) = op { - let maybe_uneval = match constant.literal { - ConstantKind::Val(..) | ConstantKind::Ty(_) => None, - ConstantKind::Unevaluated(uv, _) => Some(uv), + let maybe_uneval = match constant.const_ { + Const::Val(..) | Const::Ty(_) => None, + Const::Unevaluated(uv, _) => Some(uv), }; if let Some(uv) = maybe_uneval { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 3b5f1178db5..02b52784ede 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -580,7 +580,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } } - BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { + BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => { let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); if self.mir_def.to_def_id() == typeck_root_def_id { let args = diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 151674b2d6d..14b10ed8b9a 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -64,9 +64,9 @@ pub(crate) fn codegen_tls_ref<'tcx>( pub(crate) fn eval_mir_constant<'tcx>( fx: &FunctionCx<'_, '_, 'tcx>, - constant: &Constant<'tcx>, + constant: &ConstOperand<'tcx>, ) -> (ConstValue<'tcx>, Ty<'tcx>) { - let cv = fx.monomorphize(constant.literal); + let cv = fx.monomorphize(constant.const_); // This cannot fail because we checked all required_consts in advance. let val = cv .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span)) @@ -76,7 +76,7 @@ pub(crate) fn eval_mir_constant<'tcx>( pub(crate) fn codegen_constant_operand<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - constant: &Constant<'tcx>, + constant: &ConstOperand<'tcx>, ) -> CValue<'tcx> { let (const_val, ty) = eval_mir_constant(fx, constant); codegen_const_value(fx, const_val, ty) diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index eba90949b5e..50bbf8105fd 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -252,8 +252,8 @@ pub(crate) fn codegen_inline_asm<'tcx>( CInlineAsmOperand::Const { value } } InlineAsmOperand::SymFn { ref value } => { - let literal = fx.monomorphize(value.literal); - if let ty::FnDef(def_id, args) = *literal.ty().kind() { + let const_ = fx.monomorphize(value.const_); + if let ty::FnDef(def_id, args) = *const_.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( fx.tcx, ty::ParamEnv::reveal_all(), diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index 7a82d05ce9e..763186a58bf 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -1,4 +1,4 @@ -use rustc_middle::mir::coverage::{CounterId, MappedExpressionIndex}; +use rustc_middle::mir::coverage::{CounterId, ExpressionId, Operand}; /// Must match the layout of `LLVMRustCounterKind`. #[derive(Copy, Clone, Debug)] @@ -30,11 +30,8 @@ pub struct Counter { } impl Counter { - /// Constructs a new `Counter` of kind `Zero`. For this `CounterKind`, the - /// `id` is not used. - pub fn zero() -> Self { - Self { kind: CounterKind::Zero, id: 0 } - } + /// A `Counter` of kind `Zero`. For this counter kind, the `id` is not used. + pub(crate) const ZERO: Self = Self { kind: CounterKind::Zero, id: 0 }; /// Constructs a new `Counter` of kind `CounterValueReference`. pub fn counter_value_reference(counter_id: CounterId) -> Self { @@ -42,20 +39,16 @@ impl Counter { } /// Constructs a new `Counter` of kind `Expression`. - pub fn expression(mapped_expression_index: MappedExpressionIndex) -> Self { - Self { kind: CounterKind::Expression, id: mapped_expression_index.into() } - } - - /// Returns true if the `Counter` kind is `Zero`. - pub fn is_zero(&self) -> bool { - matches!(self.kind, CounterKind::Zero) + pub(crate) fn expression(expression_id: ExpressionId) -> Self { + Self { kind: CounterKind::Expression, id: expression_id.as_u32() } } - /// An explicitly-named function to get the ID value, making it more obvious - /// that the stored value is now 0-based. - pub fn zero_based_id(&self) -> u32 { - debug_assert!(!self.is_zero(), "`id` is undefined for CounterKind::Zero"); - self.id + pub(crate) fn from_operand(operand: Operand) -> Self { + match operand { + Operand::Zero => Self::ZERO, + Operand::Counter(id) => Self::counter_value_reference(id), + Operand::Expression(id) => Self::expression(id), + } } } @@ -81,6 +74,11 @@ pub struct CounterExpression { } impl CounterExpression { + /// The dummy expression `(0 - 0)` has a representation of all zeroes, + /// making it marginally more efficient to initialize than `(0 + 0)`. + pub(crate) const DUMMY: Self = + Self { lhs: Counter::ZERO, kind: ExprKind::Subtract, rhs: Counter::ZERO }; + pub fn new(lhs: Counter, kind: ExprKind, rhs: Counter) -> Self { Self { kind, lhs, rhs } } @@ -172,7 +170,7 @@ impl CounterMappingRegion { ) -> Self { Self { counter, - false_counter: Counter::zero(), + false_counter: Counter::ZERO, file_id, expanded_file_id: 0, start_line, @@ -220,8 +218,8 @@ impl CounterMappingRegion { end_col: u32, ) -> Self { Self { - counter: Counter::zero(), - false_counter: Counter::zero(), + counter: Counter::ZERO, + false_counter: Counter::ZERO, file_id, expanded_file_id, start_line, @@ -243,8 +241,8 @@ impl CounterMappingRegion { end_col: u32, ) -> Self { Self { - counter: Counter::zero(), - false_counter: Counter::zero(), + counter: Counter::ZERO, + false_counter: Counter::ZERO, file_id, expanded_file_id: 0, start_line, @@ -268,7 +266,7 @@ impl CounterMappingRegion { ) -> Self { Self { counter, - false_counter: Counter::zero(), + false_counter: Counter::ZERO, file_id, expanded_file_id: 0, start_line, diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index f1e68af25d4..e83110dcad4 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -1,10 +1,8 @@ use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind}; -use rustc_index::{IndexSlice, IndexVec}; -use rustc_middle::bug; -use rustc_middle::mir::coverage::{ - CodeRegion, CounterId, ExpressionId, MappedExpressionIndex, Op, Operand, -}; +use rustc_data_structures::fx::FxIndexSet; +use rustc_index::IndexVec; +use rustc_middle::mir::coverage::{CodeRegion, CounterId, ExpressionId, Op, Operand}; use rustc_middle::ty::Instance; use rustc_middle::ty::TyCtxt; @@ -128,6 +126,58 @@ impl<'tcx> FunctionCoverage<'tcx> { self.unreachable_regions.push(region) } + /// Perform some simplifications to make the final coverage mappings + /// slightly smaller. + /// + /// This method mainly exists to preserve the simplifications that were + /// already being performed by the Rust-side expression renumbering, so that + /// the resulting coverage mappings don't get worse. + pub(crate) fn simplify_expressions(&mut self) { + // The set of expressions that either were optimized out entirely, or + // have zero as both of their operands, and will therefore always have + // a value of zero. Other expressions that refer to these as operands + // can have those operands replaced with `Operand::Zero`. + let mut zero_expressions = FxIndexSet::default(); + + // For each expression, perform simplifications based on lower-numbered + // expressions, and then update the set of always-zero expressions if + // necessary. + // (By construction, expressions can only refer to other expressions + // that have lower IDs, so one simplification pass is sufficient.) + for (id, maybe_expression) in self.expressions.iter_enumerated_mut() { + let Some(expression) = maybe_expression else { + // If an expression is missing, it must have been optimized away, + // so any operand that refers to it can be replaced with zero. + zero_expressions.insert(id); + continue; + }; + + // If an operand refers to an expression that is always zero, then + // that operand can be replaced with `Operand::Zero`. + let maybe_set_operand_to_zero = |operand: &mut Operand| match &*operand { + Operand::Expression(id) if zero_expressions.contains(id) => { + *operand = Operand::Zero; + } + _ => (), + }; + maybe_set_operand_to_zero(&mut expression.lhs); + maybe_set_operand_to_zero(&mut expression.rhs); + + // Coverage counter values cannot be negative, so if an expression + // involves subtraction from zero, assume that its RHS must also be zero. + // (Do this after simplifications that could set the LHS to zero.) + if let Expression { lhs: Operand::Zero, op: Op::Subtract, .. } = expression { + expression.rhs = Operand::Zero; + } + + // After the above simplifications, if both operands are zero, then + // we know that this expression is always zero too. + if let Expression { lhs: Operand::Zero, rhs: Operand::Zero, .. } = expression { + zero_expressions.insert(id); + } + } + } + /// Return the source hash, generated from the HIR node structure, and used to indicate whether /// or not the source code structure changed between different compilations. pub fn source_hash(&self) -> u64 { @@ -146,8 +196,14 @@ impl<'tcx> FunctionCoverage<'tcx> { self.instance ); + let counter_expressions = self.counter_expressions(); + // Expression IDs are indices into `self.expressions`, and on the LLVM + // side they will be treated as indices into `counter_expressions`, so + // the two vectors should correspond 1:1. + assert_eq!(self.expressions.len(), counter_expressions.len()); + let counter_regions = self.counter_regions(); - let (counter_expressions, expression_regions) = self.expressions_with_regions(); + let expression_regions = self.expression_regions(); let unreachable_regions = self.unreachable_regions(); let counter_regions = @@ -163,149 +219,53 @@ impl<'tcx> FunctionCoverage<'tcx> { }) } - fn expressions_with_regions( - &self, - ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &CodeRegion)>) { - let mut counter_expressions = Vec::with_capacity(self.expressions.len()); - let mut expression_regions = Vec::with_capacity(self.expressions.len()); - let mut new_indexes = IndexVec::from_elem_n(None, self.expressions.len()); + /// Convert this function's coverage expression data into a form that can be + /// passed through FFI to LLVM. + fn counter_expressions(&self) -> Vec<CounterExpression> { + // We know that LLVM will optimize out any unused expressions before + // producing the final coverage map, so there's no need to do the same + // thing on the Rust side unless we're confident we can do much better. + // (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.) - // This closure converts any `Expression` operand (`lhs` or `rhs` of the `Op::Add` or - // `Op::Subtract` operation) into its native `llvm::coverage::Counter::CounterKind` type - // and value. - // - // Expressions will be returned from this function in a sequential vector (array) of - // `CounterExpression`, so the expression IDs must be mapped from their original, - // potentially sparse set of indexes. - // - // An `Expression` as an operand will have already been encountered as an `Expression` with - // operands, so its new_index will already have been generated (as a 1-up index value). - // (If an `Expression` as an operand does not have a corresponding new_index, it was - // probably optimized out, after the expression was injected into the MIR, so it will - // get a `CounterKind::Zero` instead.) - // - // In other words, an `Expression`s at any given index can include other expressions as - // operands, but expression operands can only come from the subset of expressions having - // `expression_index`s lower than the referencing `Expression`. Therefore, it is - // reasonable to look up the new index of an expression operand while the `new_indexes` - // vector is only complete up to the current `ExpressionIndex`. - type NewIndexes = IndexSlice<ExpressionId, Option<MappedExpressionIndex>>; - let id_to_counter = |new_indexes: &NewIndexes, operand: Operand| match operand { - Operand::Zero => Some(Counter::zero()), - Operand::Counter(id) => Some(Counter::counter_value_reference(id)), - Operand::Expression(id) => { - self.expressions - .get(id) - .expect("expression id is out of range") - .as_ref() - // If an expression was optimized out, assume it would have produced a count - // of zero. This ensures that expressions dependent on optimized-out - // expressions are still valid. - .map_or(Some(Counter::zero()), |_| new_indexes[id].map(Counter::expression)) - } - }; - - for (original_index, expression) in - self.expressions.iter_enumerated().filter_map(|(original_index, entry)| { - // Option::map() will return None to filter out missing expressions. This may happen - // if, for example, a MIR-instrumented expression is removed during an optimization. - entry.as_ref().map(|expression| (original_index, expression)) - }) - { - let optional_region = &expression.region; - let Expression { lhs, op, rhs, .. } = *expression; - - if let Some(Some((lhs_counter, mut rhs_counter))) = id_to_counter(&new_indexes, lhs) - .map(|lhs_counter| { - id_to_counter(&new_indexes, rhs).map(|rhs_counter| (lhs_counter, rhs_counter)) - }) - { - if lhs_counter.is_zero() && op.is_subtract() { - // The left side of a subtraction was probably optimized out. As an example, - // a branch condition might be evaluated as a constant expression, and the - // branch could be removed, dropping unused counters in the process. - // - // Since counters are unsigned, we must assume the result of the expression - // can be no more and no less than zero. An expression known to evaluate to zero - // does not need to be added to the coverage map. - // - // Coverage test `loops_branches.rs` includes multiple variations of branches - // based on constant conditional (literal `true` or `false`), and demonstrates - // that the expected counts are still correct. - debug!( - "Expression subtracts from zero (assume unreachable): \ - original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}", - original_index, lhs, op, rhs, optional_region, - ); - rhs_counter = Counter::zero(); + self.expressions + .iter() + .map(|expression| match expression { + None => { + // This expression ID was allocated, but we never saw the + // actual expression, so it must have been optimized out. + // Replace it with a dummy expression, and let LLVM take + // care of omitting it from the expression list. + CounterExpression::DUMMY } - debug_assert!( - lhs_counter.is_zero() - // Note: with `as usize` the ID _could_ overflow/wrap if `usize = u16` - || ((lhs_counter.zero_based_id() as usize) - <= usize::max(self.counters.len(), self.expressions.len())), - "lhs id={} > both counters.len()={} and expressions.len()={} - ({:?} {:?} {:?})", - lhs_counter.zero_based_id(), - self.counters.len(), - self.expressions.len(), - lhs_counter, - op, - rhs_counter, - ); - - debug_assert!( - rhs_counter.is_zero() - // Note: with `as usize` the ID _could_ overflow/wrap if `usize = u16` - || ((rhs_counter.zero_based_id() as usize) - <= usize::max(self.counters.len(), self.expressions.len())), - "rhs id={} > both counters.len()={} and expressions.len()={} - ({:?} {:?} {:?})", - rhs_counter.zero_based_id(), - self.counters.len(), - self.expressions.len(), - lhs_counter, - op, - rhs_counter, - ); - - // Both operands exist. `Expression` operands exist in `self.expressions` and have - // been assigned a `new_index`. - let mapped_expression_index = - MappedExpressionIndex::from(counter_expressions.len()); - let expression = CounterExpression::new( - lhs_counter, - match op { - Op::Add => ExprKind::Add, - Op::Subtract => ExprKind::Subtract, - }, - rhs_counter, - ); - debug!( - "Adding expression {:?} = {:?}, region: {:?}", - mapped_expression_index, expression, optional_region - ); - counter_expressions.push(expression); - new_indexes[original_index] = Some(mapped_expression_index); - if let Some(region) = optional_region { - expression_regions.push((Counter::expression(mapped_expression_index), region)); + &Some(Expression { lhs, op, rhs, .. }) => { + // Convert the operands and operator as normal. + CounterExpression::new( + Counter::from_operand(lhs), + match op { + Op::Add => ExprKind::Add, + Op::Subtract => ExprKind::Subtract, + }, + Counter::from_operand(rhs), + ) } - } else { - bug!( - "expression has one or more missing operands \ - original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}", - original_index, - lhs, - op, - rhs, - optional_region, - ); - } - } - (counter_expressions, expression_regions.into_iter()) + }) + .collect::<Vec<_>>() + } + + fn expression_regions(&self) -> Vec<(Counter, &CodeRegion)> { + // Find all of the expression IDs that weren't optimized out AND have + // an attached code region, and return the corresponding mapping as a + // counter/region pair. + self.expressions + .iter_enumerated() + .filter_map(|(id, expression)| { + let code_region = expression.as_ref()?.region.as_ref()?; + Some((Counter::expression(id), code_region)) + }) + .collect::<Vec<_>>() } fn unreachable_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> { - self.unreachable_regions.iter().map(|region| (Counter::zero(), region)) + self.unreachable_regions.iter().map(|region| (Counter::ZERO, region)) } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 8ba7a11abe5..d4e77525698 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -60,8 +60,11 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { // Encode coverage mappings and generate function records let mut function_data = Vec::new(); - for (instance, function_coverage) in function_coverage_map { + for (instance, mut function_coverage) in function_coverage_map { debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance); + function_coverage.simplify_expressions(); + let function_coverage = function_coverage; + let mangled_function_name = tcx.symbol_name(instance).name; let source_hash = function_coverage.source_hash(); let is_used = function_coverage.is_used(); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index e21148a4de1..a2190293c0b 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -660,12 +660,12 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S } _ => match ct.ty().kind() { ty::Int(ity) => { - let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty()); + let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; write!(output, "{val}") } ty::Uint(_) => { - let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty()); + let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); write!(output, "{val}") } ty::Bool => { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b738a49bf11..bd0707edfd9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1098,8 +1098,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { InlineAsmOperandRef::Const { string } } mir::InlineAsmOperand::SymFn { ref value } => { - let literal = self.monomorphize(value.literal); - if let ty::FnDef(def_id, args) = *literal.ty().kind() { + let const_ = self.monomorphize(value.const_); + if let ty::FnDef(def_id, args) = *const_.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), ty::ParamEnv::reveal_all(), diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 7fec4047a95..fde4e85f966 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -13,37 +13,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn eval_mir_constant_to_operand( &self, bx: &mut Bx, - constant: &mir::Constant<'tcx>, + constant: &mir::ConstOperand<'tcx>, ) -> OperandRef<'tcx, Bx::Value> { let val = self.eval_mir_constant(constant); let ty = self.monomorphize(constant.ty()); OperandRef::from_const(bx, val, ty) } - pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> mir::ConstValue<'tcx> { - self.monomorphize(constant.literal) + pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue<'tcx> { + self.monomorphize(constant.const_) .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span)) .expect("erroneous constant not captured by required_consts") } /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition - /// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to + /// that the given `constant` is an `Const::Unevaluated` and must be convertible to /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip. /// /// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees! pub fn eval_unevaluated_mir_constant_to_valtree( &self, - constant: &mir::Constant<'tcx>, + constant: &mir::ConstOperand<'tcx>, ) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> { - let uv = match self.monomorphize(constant.literal) { - mir::ConstantKind::Unevaluated(uv, _) => uv.shrink(), - mir::ConstantKind::Ty(c) => match c.kind() { + let uv = match self.monomorphize(constant.const_) { + mir::Const::Unevaluated(uv, _) => uv.shrink(), + mir::Const::Ty(c) => match c.kind() { // A constant that came from a const generic but was then used as an argument to old-style // simd_shuffle (passing as argument instead of as a generic param). rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)), other => span_bug!(constant.span, "{other:#?}"), }, - // We should never encounter `ConstantKind::Val` unless MIR opts (like const prop) evaluate + // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate // a constant and write that value back into `Operand`s. This could happen, but is unlikely. // Also: all users of `simd_shuffle` are on unstable and already need to take a lot of care // around intrinsics. For an issue to happen here, it would require a macro expanding to a @@ -65,7 +65,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn simd_shuffle_indices( &mut self, bx: &Bx, - constant: &mir::Constant<'tcx>, + constant: &mir::ConstOperand<'tcx>, ) -> (Bx::Value, Ty<'tcx>) { let ty = self.monomorphize(constant.ty()); let val = self diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index f16aea6f34b..14b9894aad5 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -3,7 +3,7 @@ use rustc_hir::{LangItem, CRATE_HIR_ID}; use rustc_middle::mir; use rustc_middle::mir::interpret::PointerArithmetic; use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::INVALID_ALIGNMENT; use std::borrow::Borrow; use std::hash::Hash; @@ -596,7 +596,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _bin_op: mir::BinOp, _left: &ImmTy<'tcx>, _right: &ImmTy<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> { throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time"); } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index bd897ffaafc..b9f88cf6352 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -24,41 +24,44 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { cast_ty: Ty<'tcx>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { + // `cast_ty` will often be the same as `dest.ty`, but not always, since subtyping is still + // possible. + let cast_layout = + if cast_ty == dest.layout.ty { dest.layout } else { self.layout_of(cast_ty)? }; // FIXME: In which cases should we trigger UB when the source is uninit? match cast_kind { CastKind::PointerCoercion(PointerCoercion::Unsize) => { - let cast_ty = self.layout_of(cast_ty)?; - self.unsize_into(src, cast_ty, dest)?; + self.unsize_into(src, cast_layout, dest)?; } CastKind::PointerExposeAddress => { let src = self.read_immediate(src)?; - let res = self.pointer_expose_address_cast(&src, cast_ty)?; - self.write_immediate(res, dest)?; + let res = self.pointer_expose_address_cast(&src, cast_layout)?; + self.write_immediate(*res, dest)?; } CastKind::PointerFromExposedAddress => { let src = self.read_immediate(src)?; - let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?; - self.write_immediate(res, dest)?; + let res = self.pointer_from_exposed_address_cast(&src, cast_layout)?; + self.write_immediate(*res, dest)?; } CastKind::IntToInt | CastKind::IntToFloat => { let src = self.read_immediate(src)?; - let res = self.int_to_int_or_float(&src, cast_ty)?; - self.write_immediate(res, dest)?; + let res = self.int_to_int_or_float(&src, cast_layout)?; + self.write_immediate(*res, dest)?; } CastKind::FloatToFloat | CastKind::FloatToInt => { let src = self.read_immediate(src)?; - let res = self.float_to_float_or_int(&src, cast_ty)?; - self.write_immediate(res, dest)?; + let res = self.float_to_float_or_int(&src, cast_layout)?; + self.write_immediate(*res, dest)?; } CastKind::FnPtrToPtr | CastKind::PtrToPtr => { let src = self.read_immediate(src)?; - let res = self.ptr_to_ptr(&src, cast_ty)?; - self.write_immediate(res, dest)?; + let res = self.ptr_to_ptr(&src, cast_layout)?; + self.write_immediate(*res, dest)?; } CastKind::PointerCoercion( @@ -87,7 +90,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let fn_ptr = self.fn_ptr(FnVal::Instance(instance)); self.write_pointer(fn_ptr, dest)?; } - _ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty), + _ => span_bug!(self.cur_span(), "reify fn pointer on {}", src.layout.ty), } } @@ -98,7 +101,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // No change to value self.write_immediate(*src, dest)?; } - _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty), + _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {}", cast_ty), } } @@ -119,7 +122,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let fn_ptr = self.fn_ptr(FnVal::Instance(instance)); self.write_pointer(fn_ptr, dest)?; } - _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty), + _ => span_bug!(self.cur_span(), "closure fn pointer on {}", src.layout.ty), } } @@ -140,6 +143,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { CastKind::Transmute => { assert!(src.layout.is_sized()); assert!(dest.layout.is_sized()); + assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely... if src.layout.size != dest.layout.size { let src_bytes = src.layout.size.bytes(); let dest_bytes = dest.layout.size.bytes(); @@ -164,62 +168,61 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn int_to_int_or_float( &self, src: &ImmTy<'tcx, M::Provenance>, - cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate<M::Provenance>> { + cast_to: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool()); - assert!(cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char()); + assert!(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() || cast_to.ty.is_char()); - Ok(self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?.into()) + Ok(ImmTy::from_scalar( + self.cast_from_int_like(src.to_scalar(), src.layout, cast_to.ty)?, + cast_to, + )) } /// Handles 'FloatToFloat' and 'FloatToInt' casts. pub fn float_to_float_or_int( &self, src: &ImmTy<'tcx, M::Provenance>, - cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate<M::Provenance>> { + cast_to: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { use rustc_type_ir::sty::TyKind::*; - match src.layout.ty.kind() { + let val = match src.layout.ty.kind() { // Floating point - Float(FloatTy::F32) => { - return Ok(self.cast_from_float(src.to_scalar().to_f32()?, cast_ty).into()); - } - Float(FloatTy::F64) => { - return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into()); - } + Float(FloatTy::F32) => self.cast_from_float(src.to_scalar().to_f32()?, cast_to.ty), + Float(FloatTy::F64) => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty), _ => { - bug!("Can't cast 'Float' type into {:?}", cast_ty); + bug!("Can't cast 'Float' type into {}", cast_to.ty); } - } + }; + Ok(ImmTy::from_scalar(val, cast_to)) } /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. pub fn ptr_to_ptr( &self, src: &ImmTy<'tcx, M::Provenance>, - cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate<M::Provenance>> { + cast_to: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_any_ptr()); - assert!(cast_ty.is_unsafe_ptr()); + assert!(cast_to.ty.is_unsafe_ptr()); // Handle casting any ptr to raw ptr (might be a fat ptr). - let dest_layout = self.layout_of(cast_ty)?; - if dest_layout.size == src.layout.size { + if cast_to.size == src.layout.size { // Thin or fat pointer that just hast the ptr kind of target type changed. - return Ok(**src); + return Ok(ImmTy::from_immediate(**src, cast_to)); } else { // Casting the metadata away from a fat ptr. assert_eq!(src.layout.size, 2 * self.pointer_size()); - assert_eq!(dest_layout.size, self.pointer_size()); + assert_eq!(cast_to.size, self.pointer_size()); assert!(src.layout.ty.is_unsafe_ptr()); return match **src { - Immediate::ScalarPair(data, _) => Ok(data.into()), + Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, cast_to)), Immediate::Scalar(..) => span_bug!( self.cur_span(), - "{:?} input to a fat-to-thin cast ({:?} -> {:?})", + "{:?} input to a fat-to-thin cast ({} -> {})", *src, src.layout.ty, - cast_ty + cast_to.ty ), Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; @@ -229,10 +232,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn pointer_expose_address_cast( &mut self, src: &ImmTy<'tcx, M::Provenance>, - cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate<M::Provenance>> { + cast_to: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_)); - assert!(cast_ty.is_integral()); + assert!(cast_to.ty.is_integral()); let scalar = src.to_scalar(); let ptr = scalar.to_pointer(self)?; @@ -240,16 +243,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(ptr) => M::expose_ptr(self, ptr)?, Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP. }; - Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) + Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to)) } pub fn pointer_from_exposed_address_cast( &self, src: &ImmTy<'tcx, M::Provenance>, - cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate<M::Provenance>> { + cast_to: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_integral()); - assert_matches!(cast_ty.kind(), ty::RawPtr(_)); + assert_matches!(cast_to.ty.kind(), ty::RawPtr(_)); // First cast to usize. let scalar = src.to_scalar(); @@ -258,12 +261,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Then turn address into pointer. let ptr = M::ptr_from_addr_cast(&self, addr)?; - Ok(Scalar::from_maybe_pointer(ptr, self).into()) + Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to)) } /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input /// type (basically everything with a scalar layout) to int/float/char types. - pub fn cast_from_int_like( + fn cast_from_int_like( &self, scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout) src_layout: TyAndLayout<'tcx>, @@ -298,7 +301,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Casts to bool are not permitted by rustc, no need to handle them here. - _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty), + _ => span_bug!(self.cur_span(), "invalid int to {} cast", cast_ty), }) } @@ -331,7 +334,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // float -> f64 Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value), // That's it. - _ => span_bug!(self.cur_span(), "invalid float to {:?} cast", dest_ty), + _ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty), } } @@ -390,7 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { span_bug!( self.cur_span(), - "invalid pointer unsizing {:?} -> {:?}", + "invalid pointer unsizing {} -> {}", src.layout.ty, cast_ty ) @@ -404,7 +407,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { cast_ty: TyAndLayout<'tcx>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty); + trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty); match (&src.layout.ty.kind(), &cast_ty.ty.kind()) { (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. })) | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => { diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 440ee06e7fe..49e01728ff4 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -76,7 +76,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); let variant_index_relative_val = ImmTy::from_uint(variant_index_relative, tag_layout); - let tag_val = self.binary_op( + let tag_val = self.wrapping_binary_op( mir::BinOp::Add, &variant_index_relative_val, &niche_start_val, @@ -153,19 +153,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Figure out which discriminant and variant this corresponds to. let index = match *tag_encoding { TagEncoding::Direct => { - let scalar = tag_val.to_scalar(); // Generate a specific error if `tag_val` is not an integer. // (`tag_bits` itself is only used for error messages below.) - let tag_bits = scalar + let tag_bits = tag_val + .to_scalar() .try_to_int() .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))? .assert_bits(tag_layout.size); // Cast bits from tag layout to discriminant layout. // After the checks we did above, this cannot fail, as // discriminants are int-like. - let discr_val = - self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap(); - let discr_bits = discr_val.assert_bits(discr_layout.size); + let discr_val = self.int_to_int_or_float(&tag_val, discr_layout).unwrap(); + let discr_bits = discr_val.to_scalar().assert_bits(discr_layout.size); // Convert discriminant to variant index, and catch invalid discriminants. let index = match *ty.kind() { ty::Adt(adt, _) => { @@ -208,7 +207,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let tag_val = ImmTy::from_uint(tag_bits, tag_layout); let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); let variant_index_relative_val = - self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?; + self.wrapping_binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?; let variant_index_relative = variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size); // Check if this is in the range that indicates an actual discriminant. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index cb14e165b5c..83f2052d0f8 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -416,7 +416,7 @@ pub(super) fn from_known_layout<'tcx>( if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) { span_bug!( tcx.span, - "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}", + "expected type differs from actual type.\nexpected: {}\nactual: {}", known_layout.ty, check_layout.ty, ); @@ -712,7 +712,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::Foreign(_) => Ok(None), - _ => span_bug!(self.cur_span(), "size_and_align_of::<{:?}> not supported", layout.ty), + _ => span_bug!(self.cur_span(), "size_and_align_of::<{}> not supported", layout.ty), } } #[inline] @@ -982,7 +982,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::Bound(..) | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("`is_very_trivially_sized` applied to unexpected type: {:?}", ty) + bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty) } } } @@ -1089,7 +1089,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn eval_mir_constant( &self, - val: &mir::ConstantKind<'tcx>, + val: &mir::Const<'tcx>, span: Option<Span>, layout: Option<TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 775a834f2ee..2b26dbbba98 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -307,7 +307,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let dist = { // Addresses are unsigned, so this is a `usize` computation. We have to do the // overflow check separately anyway. - let (val, overflowed, _ty) = { + let (val, overflowed) = { let a_offset = ImmTy::from_uint(a_offset, usize_layout); let b_offset = ImmTy::from_uint(b_offset, usize_layout); self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)? @@ -324,7 +324,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The signed form of the intrinsic allows this. If we interpret the // difference as isize, we'll get the proper signed difference. If that // seems *positive*, they were more than isize::MAX apart. - let dist = val.to_target_isize(self)?; + let dist = val.to_scalar().to_target_isize(self)?; if dist >= 0 { throw_ub_custom!( fluent::const_eval_offset_from_underflow, @@ -334,7 +334,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { dist } else { // b >= a - let dist = val.to_target_isize(self)?; + let dist = val.to_scalar().to_target_isize(self)?; // If converting to isize produced a *negative* result, we had an overflow // because they were more than isize::MAX apart. if dist < 0 { @@ -504,9 +504,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`. // First, check x % y != 0 (or if that computation overflows). - let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?; + let (res, overflow) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?; assert!(!overflow); // All overflow is UB, so this should never return on overflow. - if res.assert_bits(a.layout.size) != 0 { + if res.to_scalar().assert_bits(a.layout.size) != 0 { throw_ub_custom!( fluent::const_eval_exact_div_has_remainder, a = format!("{a}"), @@ -524,7 +524,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { r: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Scalar<M::Provenance>> { assert!(matches!(mir_op, BinOp::Add | BinOp::Sub)); - let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?; + let (val, overflowed) = self.overflowing_binary_op(mir_op, l, r)?; Ok(if overflowed { let size = l.layout.size; let num_bits = size.bits(); @@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } } else { - val + val.to_scalar() }) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index c9fd2102418..aaa674a598f 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -9,7 +9,7 @@ use std::hash::Hash; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::DefId; use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi as CallAbi; @@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment; use super::{ AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx, - InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance, Scalar, + InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance, }; /// Data returned by Machine::stack_pop, @@ -238,7 +238,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { bin_op: mir::BinOp, left: &ImmTy<'tcx, Self::Provenance>, right: &ImmTy<'tcx, Self::Provenance>, - ) -> InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)>; + ) -> InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)>; /// Called before writing the specified `local` of the `frame`. /// Since writing a ZST is not actually accessing memory or locals, this is never invoked diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index fdda98a50e8..a32ea204f98 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -8,7 +8,7 @@ use either::{Either, Left, Right}; use rustc_hir::def::Namespace; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; -use rustc_middle::ty::{ConstInt, Ty}; +use rustc_middle::ty::{ConstInt, Ty, TyCtxt}; use rustc_middle::{mir, ty}; use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size}; @@ -165,7 +165,15 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline(always)] pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self { - debug_assert!(layout.is_sized(), "immediates must be sized"); + debug_assert!( + match (imm, layout.abi) { + (Immediate::Scalar(..), Abi::Scalar(..)) => true, + (Immediate::ScalarPair(..), Abi::ScalarPair(..)) => true, + (Immediate::Uninit, _) if layout.is_sized() => true, + _ => false, + }, + "immediate {imm:?} does not fit to layout {layout:?}", + ); ImmTy { imm, layout } } @@ -195,6 +203,12 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { } #[inline] + pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self { + let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx.types.bool)).unwrap(); + Self::from_scalar(Scalar::from_bool(b), layout) + } + + #[inline] pub fn to_const_int(self) -> ConstInt { assert!(self.layout.ty.is_integral()); let int = self.to_scalar().assert_int(); @@ -448,7 +462,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { alloc_range(Size::ZERO, size), /*read_provenance*/ matches!(s, abi::Pointer(_)), )?; - Some(ImmTy { imm: scalar.into(), layout: mplace.layout }) + Some(ImmTy::from_scalar(scalar, mplace.layout)) } Abi::ScalarPair( abi::Scalar::Initialized { value: a, .. }, @@ -468,7 +482,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { alloc_range(b_offset, b_size), /*read_provenance*/ matches!(b, abi::Pointer(_)), )?; - Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout }) + Some(ImmTy::from_immediate(Immediate::ScalarPair(a_val, b_val), mplace.layout)) } _ => { // Neither a scalar nor scalar pair. @@ -514,11 +528,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Abi::Scalar(abi::Scalar::Initialized { .. }) | Abi::ScalarPair(abi::Scalar::Initialized { .. }, abi::Scalar::Initialized { .. }) ) { - span_bug!( - self.cur_span(), - "primitive read not possible for type: {:?}", - op.layout().ty - ); + span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty); } let imm = self.read_immediate_raw(op)?.right().unwrap(); if matches!(*imm, Immediate::Uninit) { @@ -669,7 +679,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )?)?, op.layout, ), - "eval_place of a MIR place with type {:?} produced an interpreter operand with type {:?}", + "eval_place of a MIR place with type {:?} produced an interpreter operand with type {}", mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, op.layout.ty, ); @@ -692,7 +702,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Constant(constant) => { let c = - self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?; + self.subst_from_current_frame_and_normalize_erasing_regions(constant.const_)?; // This can still fail: // * During ConstProp, with `TooGeneric` or since the `required_consts` were not all diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index eb064578067..b084864f3a7 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -1,7 +1,7 @@ use rustc_apfloat::Float; use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpResult, Scalar}; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_span::symbol::sym; use rustc_target::abi::Abi; @@ -20,9 +20,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { right: &ImmTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?; + let (val, overflowed) = self.overflowing_binary_op(op, &left, &right)?; debug_assert_eq!( - Ty::new_tup(self.tcx.tcx, &[ty, self.tcx.types.bool]), + Ty::new_tup(self.tcx.tcx, &[val.layout.ty, self.tcx.types.bool]), dest.layout.ty, "type mismatch for result of {op:?}", ); @@ -30,7 +30,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Abi::ScalarPair(..) = dest.layout.abi { // We can use the optimized path and avoid `place_field` (which might do // `force_allocation`). - let pair = Immediate::ScalarPair(val, Scalar::from_bool(overflowed)); + let pair = Immediate::ScalarPair(val.to_scalar(), Scalar::from_bool(overflowed)); self.write_immediate(pair, dest)?; } else { assert!(self.tcx.sess.opts.unstable_opts.randomize_layout); @@ -38,7 +38,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // do a component-wise write here. This code path is slower than the above because // `place_field` will have to `force_allocate` locals here. let val_field = self.project_field(dest, 0)?; - self.write_scalar(val, &val_field)?; + self.write_scalar(val.to_scalar(), &val_field)?; let overflowed_field = self.project_field(dest, 1)?; self.write_scalar(Scalar::from_bool(overflowed), &overflowed_field)?; } @@ -54,9 +54,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { right: &ImmTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?; - assert_eq!(ty, dest.layout.ty, "type mismatch for result of {op:?}"); - self.write_scalar(val, dest) + let val = self.wrapping_binary_op(op, left, right)?; + assert_eq!(val.layout.ty, dest.layout.ty, "type mismatch for result of {op:?}"); + self.write_immediate(*val, dest) } } @@ -66,7 +66,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, l: char, r: char, - ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) { + ) -> (ImmTy<'tcx, M::Provenance>, bool) { use rustc_middle::mir::BinOp::*; let res = match bin_op { @@ -78,7 +78,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ge => l >= r, _ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op), }; - (Scalar::from_bool(res), false, self.tcx.types.bool) + (ImmTy::from_bool(res, *self.tcx), false) } fn binary_bool_op( @@ -86,7 +86,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, l: bool, r: bool, - ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) { + ) -> (ImmTy<'tcx, M::Provenance>, bool) { use rustc_middle::mir::BinOp::*; let res = match bin_op { @@ -101,33 +101,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { BitXor => l ^ r, _ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op), }; - (Scalar::from_bool(res), false, self.tcx.types.bool) + (ImmTy::from_bool(res, *self.tcx), false) } fn binary_float_op<F: Float + Into<Scalar<M::Provenance>>>( &self, bin_op: mir::BinOp, - ty: Ty<'tcx>, + layout: TyAndLayout<'tcx>, l: F, r: F, - ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) { + ) -> (ImmTy<'tcx, M::Provenance>, bool) { use rustc_middle::mir::BinOp::*; - let (val, ty) = match bin_op { - Eq => (Scalar::from_bool(l == r), self.tcx.types.bool), - Ne => (Scalar::from_bool(l != r), self.tcx.types.bool), - Lt => (Scalar::from_bool(l < r), self.tcx.types.bool), - Le => (Scalar::from_bool(l <= r), self.tcx.types.bool), - Gt => (Scalar::from_bool(l > r), self.tcx.types.bool), - Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool), - Add => ((l + r).value.into(), ty), - Sub => ((l - r).value.into(), ty), - Mul => ((l * r).value.into(), ty), - Div => ((l / r).value.into(), ty), - Rem => ((l % r).value.into(), ty), + let val = match bin_op { + Eq => ImmTy::from_bool(l == r, *self.tcx), + Ne => ImmTy::from_bool(l != r, *self.tcx), + Lt => ImmTy::from_bool(l < r, *self.tcx), + Le => ImmTy::from_bool(l <= r, *self.tcx), + Gt => ImmTy::from_bool(l > r, *self.tcx), + Ge => ImmTy::from_bool(l >= r, *self.tcx), + Add => ImmTy::from_scalar((l + r).value.into(), layout), + Sub => ImmTy::from_scalar((l - r).value.into(), layout), + Mul => ImmTy::from_scalar((l * r).value.into(), layout), + Div => ImmTy::from_scalar((l / r).value.into(), layout), + Rem => ImmTy::from_scalar((l % r).value.into(), layout), _ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op), }; - (val, false, ty) + (val, false) } fn binary_int_op( @@ -138,7 +138,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { left_layout: TyAndLayout<'tcx>, r: u128, right_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { use rustc_middle::mir::BinOp::*; let throw_ub_on_overflow = match bin_op { @@ -200,19 +200,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ); } - return Ok((Scalar::from_uint(truncated, left_layout.size), overflow, left_layout.ty)); + return Ok((ImmTy::from_uint(truncated, left_layout), overflow)); } // For the remaining ops, the types must be the same on both sides if left_layout.ty != right_layout.ty { span_bug!( self.cur_span(), - "invalid asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})", - bin_op, - l, - left_layout.ty, - r, - right_layout.ty, + "invalid asymmetric binary op {bin_op:?}: {l:?} ({l_ty}), {r:?} ({r_ty})", + l_ty = left_layout.ty, + r_ty = right_layout.ty, ) } @@ -230,7 +227,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(op) = op { let l = self.sign_extend(l, left_layout) as i128; let r = self.sign_extend(r, right_layout) as i128; - return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool)); + return Ok((ImmTy::from_bool(op(&l, &r), *self.tcx), false)); } let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op { Div if r == 0 => throw_ub!(DivisionByZero), @@ -267,22 +264,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if overflow && let Some(intrinsic_name) = throw_ub_on_overflow { throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name); } - return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty)); + return Ok((ImmTy::from_uint(truncated, left_layout), overflow)); } } - let (val, ty) = match bin_op { - Eq => (Scalar::from_bool(l == r), self.tcx.types.bool), - Ne => (Scalar::from_bool(l != r), self.tcx.types.bool), + let val = match bin_op { + Eq => ImmTy::from_bool(l == r, *self.tcx), + Ne => ImmTy::from_bool(l != r, *self.tcx), - Lt => (Scalar::from_bool(l < r), self.tcx.types.bool), - Le => (Scalar::from_bool(l <= r), self.tcx.types.bool), - Gt => (Scalar::from_bool(l > r), self.tcx.types.bool), - Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool), + Lt => ImmTy::from_bool(l < r, *self.tcx), + Le => ImmTy::from_bool(l <= r, *self.tcx), + Gt => ImmTy::from_bool(l > r, *self.tcx), + Ge => ImmTy::from_bool(l >= r, *self.tcx), - BitOr => (Scalar::from_uint(l | r, size), left_layout.ty), - BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty), - BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty), + BitOr => ImmTy::from_uint(l | r, left_layout), + BitAnd => ImmTy::from_uint(l & r, left_layout), + BitXor => ImmTy::from_uint(l ^ r, left_layout), Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Rem | Div => { assert!(!left_layout.abi.is_signed()); @@ -304,12 +301,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if overflow && let Some(intrinsic_name) = throw_ub_on_overflow { throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name); } - return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty)); + return Ok((ImmTy::from_uint(truncated, left_layout), overflow)); } _ => span_bug!( self.cur_span(), - "invalid binary op {:?}: {:?}, {:?} (both {:?})", + "invalid binary op {:?}: {:?}, {:?} (both {})", bin_op, l, r, @@ -317,7 +314,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ), }; - Ok((val, false, ty)) + Ok((val, false)) } fn binary_ptr_op( @@ -325,7 +322,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { use rustc_middle::mir::BinOp::*; match bin_op { @@ -336,7 +333,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?; - Ok((Scalar::from_maybe_pointer(offset_ptr, self), false, left.layout.ty)) + Ok(( + ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout), + false, + )) } // Fall back to machine hook so Miri can support more pointer ops. @@ -344,16 +344,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - /// Returns the result of the specified operation, whether it overflowed, and - /// the result type. + /// Returns the result of the specified operation, and whether it overflowed. pub fn overflowing_binary_op( &self, bin_op: mir::BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { trace!( - "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", + "Running binary op {:?}: {:?} ({}), {:?} ({})", bin_op, *left, left.layout.ty, @@ -376,15 +375,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } ty::Float(fty) => { assert_eq!(left.layout.ty, right.layout.ty); - let ty = left.layout.ty; + let layout = left.layout; let left = left.to_scalar(); let right = right.to_scalar(); Ok(match fty { FloatTy::F32 => { - self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?) + self.binary_float_op(bin_op, layout, left.to_f32()?, right.to_f32()?) } FloatTy::F64 => { - self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?) + self.binary_float_op(bin_op, layout, left.to_f64()?, right.to_f64()?) } }) } @@ -392,7 +391,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // the RHS type can be different, e.g. for shifts -- but it has to be integral, too assert!( right.layout.ty.is_integral(), - "Unexpected types for BinOp: {:?} {:?} {:?}", + "Unexpected types for BinOp: {} {:?} {}", left.layout.ty, bin_op, right.layout.ty @@ -407,7 +406,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // (Even when both sides are pointers, their type might differ, see issue #91636) assert!( right.layout.ty.is_any_ptr() || right.layout.ty.is_integral(), - "Unexpected types for BinOp: {:?} {:?} {:?}", + "Unexpected types for BinOp: {} {:?} {}", left.layout.ty, bin_op, right.layout.ty @@ -417,22 +416,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => span_bug!( self.cur_span(), - "Invalid MIR: bad LHS type for binop: {:?}", + "Invalid MIR: bad LHS type for binop: {}", left.layout.ty ), } } - /// Typed version of `overflowing_binary_op`, returning an `ImmTy`. Also ignores overflows. #[inline] - pub fn binary_op( + pub fn wrapping_binary_op( &self, bin_op: mir::BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?; - Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) + let (val, _overflow) = self.overflowing_binary_op(bin_op, left, right)?; + Ok(val) } /// Returns the result of the specified operation, whether it overflowed, and @@ -441,12 +439,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, un_op: mir::UnOp, val: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { use rustc_middle::mir::UnOp::*; let layout = val.layout; let val = val.to_scalar(); - trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty); + trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty); match layout.ty.kind() { ty::Bool => { @@ -455,7 +453,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Not => !val, _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op), }; - Ok((Scalar::from_bool(res), false, self.tcx.types.bool)) + Ok((ImmTy::from_bool(res, *self.tcx), false)) } ty::Float(fty) => { let res = match (un_op, fty) { @@ -463,7 +461,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op), }; - Ok((res, false, layout.ty)) + Ok((ImmTy::from_scalar(res, layout), false)) } _ => { assert!(layout.ty.is_integral()); @@ -482,17 +480,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (truncated, overflow || self.sign_extend(truncated, layout) != res) } }; - Ok((Scalar::from_uint(res, layout.size), overflow, layout.ty)) + Ok((ImmTy::from_uint(res, layout), overflow)) } } } - pub fn unary_op( + #[inline] + pub fn wrapping_unary_op( &self, un_op: mir::UnOp, val: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?; - Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) + let (val, _overflow) = self.overflowing_unary_op(un_op, val)?; + Ok(val) } } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index fb9aa9d3abe..503004cbbe1 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -460,7 +460,7 @@ where trace!("deref to {} on {:?}", val.layout.ty, *val); if val.layout.ty.is_box() { - bug!("dereferencing {:?}", val.layout.ty); + bug!("dereferencing {}", val.layout.ty); } let mplace = self.ref_to_mplace(&val)?; @@ -582,7 +582,7 @@ where )?)?, place.layout, ), - "eval_place of a MIR place with type {:?} produced an interpreter place with type {:?}", + "eval_place of a MIR place with type {:?} produced an interpreter place with type {}", mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, place.layout.ty, ); @@ -835,7 +835,7 @@ where if !allow_transmute && !layout_compat { span_bug!( self.cur_span(), - "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", + "type mismatch when copying!\nsrc: {},\ndest: {}", src.layout().ty, dest.layout().ty, ); diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index cf1f7ff75e1..284e13407f7 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -177,7 +177,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { UnaryOp(un_op, ref operand) => { // The operand always has the same type as the result. let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?; - let val = self.unary_op(un_op, &val)?; + let val = self.wrapping_unary_op(un_op, &val)?; assert_eq!(val.layout, dest.layout, "layout mismatch for result of {un_op:?}"); self.write_immediate(*val, &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index e15499bc68d..578dd6622aa 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -98,14 +98,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { for (const_int, target) in targets.iter() { // Compare using MIR BinOp::Eq, to also support pointer values. // (Avoiding `self.binary_op` as that does some redundant layout computation.) - let res = self - .overflowing_binary_op( - mir::BinOp::Eq, - &discr, - &ImmTy::from_uint(const_int, discr.layout), - )? - .0; - if res.to_bool()? { + let res = self.wrapping_binary_op( + mir::BinOp::Eq, + &discr, + &ImmTy::from_uint(const_int, discr.layout), + )?; + if res.to_scalar().to_bool()? { target_block = target; break; } @@ -151,7 +149,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => span_bug!( terminator.source_info.span, - "invalid callee of type {:?}", + "invalid callee of type {}", func.layout.ty ), }; @@ -681,10 +679,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.storage_live(local)?; // Must be a tuple let ty::Tuple(fields) = ty.kind() else { - span_bug!( - self.cur_span(), - "non-tuple type for `spread_arg`: {ty:?}" - ) + span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}") }; for (i, field_ty) in fields.iter().enumerate() { let dest = dest.project_deeper( @@ -926,7 +921,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { target: mir::BasicBlock, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { - trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance); + trace!("drop_in_place: {:?},\n instance={:?}", place, instance); // We take the address of the object. This may well be unaligned, which is fine // for us here. However, unaligned accesses will probably make the actual drop // implementation fail -- a problem shared by rustc. diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index f288ddc25d3..129e74425b6 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -167,7 +167,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { false } - hir::ConstContext::Const | hir::ConstContext::Static(_) => { + hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => { let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx) .into_engine(ccx.tcx, &ccx.body) .iterate_to_fixpoint() diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index b1b2859ef9d..34e9b76c484 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -346,8 +346,8 @@ where }; // Check the qualifs of the value of `const` items. - let uneval = match constant.literal { - ConstantKind::Ty(ct) + let uneval = match constant.const_ { + Const::Ty(ct) if matches!( ct.kind(), ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_) @@ -355,11 +355,11 @@ where { None } - ConstantKind::Ty(c) => { + Const::Ty(c) => { bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c) } - ConstantKind::Unevaluated(uv, _) => Some(uv), - ConstantKind::Val(..) => None, + Const::Unevaluated(uv, _) => Some(uv), + Const::Val(..) => None, }; if let Some(mir::UnevaluatedConst { def, args: _, promoted }) = uneval { @@ -383,5 +383,5 @@ where } // Otherwise use the qualifs of the type. - Q::in_any_value_of_ty(cx, constant.literal.ty()) + Q::in_any_value_of_ty(cx, constant.const_.ty()) } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index d79c65f1d1f..4a9977add78 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -372,7 +372,7 @@ impl<'tcx> Validator<'_, 'tcx> { StatementKind::Assign(box ( _, Rvalue::Use(Operand::Constant(c)), - )) => c.literal.try_eval_target_usize(self.tcx, self.param_env), + )) => c.const_.try_eval_target_usize(self.tcx, self.param_env), _ => None, } } else { @@ -554,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> { // Integer division: the RHS must be a non-zero const. let const_val = match rhs { Operand::Constant(c) => { - c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty) + c.const_.try_eval_bits(self.tcx, self.param_env) } _ => None, }; @@ -644,7 +644,7 @@ impl<'tcx> Validator<'_, 'tcx> { // Everywhere else, we require `#[rustc_promotable]` on the callee. let promote_all_const_fn = matches!( self.const_kind, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false }) ); if !promote_all_const_fn { if let ty::FnDef(def_id, _) = *fn_ty.kind() { @@ -766,10 +766,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { if self.keep_original { rhs.clone() } else { - let unit = Rvalue::Use(Operand::Constant(Box::new(Constant { + let unit = Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: statement.source_info.span, user_ty: None, - literal: ConstantKind::zero_sized(self.tcx.types.unit), + const_: Const::zero_sized(self.tcx.types.unit), }))); mem::replace(rhs, unit) }, @@ -844,10 +844,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def)); let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) }; - Operand::Constant(Box::new(Constant { + Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - literal: ConstantKind::Unevaluated(uneval, ty), + const_: Const::Unevaluated(uneval, ty), })) }; @@ -1041,8 +1041,8 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>( if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) = &block.terminator { - if let Operand::Constant(box Constant { literal, .. }) = func { - if let ty::FnDef(def_id, _) = *literal.ty().kind() { + if let Operand::Constant(box ConstOperand { const_, .. }) = func { + if let ty::FnDef(def_id, _) = *const_.ty().kind() { if destination == place { if ccx.tcx.is_const_fn(def_id) { return true; diff --git a/compiler/rustc_data_structures/src/flock/unix.rs b/compiler/rustc_data_structures/src/flock/unix.rs index 4e5297d582e..eff9e8f838f 100644 --- a/compiler/rustc_data_structures/src/flock/unix.rs +++ b/compiler/rustc_data_structures/src/flock/unix.rs @@ -21,8 +21,16 @@ impl Lock { let lock_type = if exclusive { libc::F_WRLCK } else { libc::F_RDLCK }; let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = lock_type as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; + #[cfg(not(all(target_os = "hurd", target_arch = "x86")))] + { + flock.l_type = lock_type as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + } + #[cfg(all(target_os = "hurd", target_arch = "x86"))] + { + flock.l_type = lock_type as libc::c_int; + flock.l_whence = libc::SEEK_SET as libc::c_int; + } flock.l_start = 0; flock.l_len = 0; @@ -39,8 +47,16 @@ impl Lock { impl Drop for Lock { fn drop(&mut self) { let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = libc::F_UNLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; + #[cfg(not(all(target_os = "hurd", target_arch = "x86")))] + { + flock.l_type = libc::F_UNLCK as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + } + #[cfg(all(target_os = "hurd", target_arch = "x86"))] + { + flock.l_type = libc::F_UNLCK as libc::c_int; + flock.l_whence = libc::SEEK_SET as libc::c_int; + } flock.l_start = 0; flock.l_len = 0; diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 3fd087b1d5e..470f318eb33 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -151,7 +151,12 @@ impl fmt::Display for DiagnosticLocation { #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] pub enum DiagnosticId { Error(String), - Lint { name: String, has_future_breakage: bool, is_force_warn: bool }, + Lint { + name: String, + /// Indicates whether this lint should show up in cargo's future breakage report. + has_future_breakage: bool, + is_force_warn: bool, + }, } /// A "sub"-diagnostic attached to a parent diagnostic. @@ -301,6 +306,7 @@ impl Diagnostic { } } + /// Indicates whether this diagnostic should show up in cargo's future breakage report. pub fn has_future_breakage(&self) -> bool { match self.code { Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage, diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index a170e3a8943..4f77f09b26e 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -161,7 +161,7 @@ impl IntoDiagnosticArg for hir::ConstContext { DiagnosticArgValue::Str(Cow::Borrowed(match self { hir::ConstContext::ConstFn => "const_fn", hir::ConstContext::Static(_) => "static", - hir::ConstContext::Const => "const", + hir::ConstContext::Const { .. } => "const", })) } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 990bd2d1cc9..b747a62b864 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -519,7 +519,7 @@ pub struct HandlerFlags { /// If false, warning-level lints are suppressed. /// (rustc: see `--allow warnings` and `--cap-lints`) pub can_emit_warnings: bool, - /// If true, error-level diagnostics are upgraded to bug-level. + /// If Some, the Nth error-level diagnostic is upgraded to bug-level. /// (rustc: see `-Z treat-err-as-bug`) pub treat_err_as_bug: Option<NonZeroUsize>, /// If true, immediately emit diagnostics that would otherwise be buffered. @@ -1719,19 +1719,17 @@ impl HandlerInner { match ( self.err_count() + self.lint_err_count, self.delayed_bug_count(), - self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0), + self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(), ) { (1, 0, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), (0, 1, 1) => panic!("aborting due delayed bug with `-Z treat-err-as-bug=1`"), - (count, delayed_count, as_bug) => { + (count, delayed_count, val) => { if delayed_count > 0 { panic!( - "aborting after {count} errors and {delayed_count} delayed bugs due to `-Z treat-err-as-bug={as_bug}`", + "aborting after {count} errors and {delayed_count} delayed bugs due to `-Z treat-err-as-bug={val}`", ) } else { - panic!( - "aborting after {count} errors due to `-Z treat-err-as-bug={as_bug}`", - ) + panic!("aborting after {count} errors due to `-Z treat-err-as-bug={val}`") } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index cb78da42597..3eec66611ed 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1581,8 +1581,8 @@ pub enum BodyOwnerKind { /// Closures Closure, - /// Constants and associated constants. - Const, + /// Constants and associated constants, also including inline constants. + Const { inline: bool }, /// Initializer of a `static` item. Static(Mutability), @@ -1592,7 +1592,7 @@ impl BodyOwnerKind { pub fn is_fn_or_closure(self) -> bool { match self { BodyOwnerKind::Fn | BodyOwnerKind::Closure => true, - BodyOwnerKind::Const | BodyOwnerKind::Static(_) => false, + BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false, } } } @@ -1615,7 +1615,7 @@ pub enum ConstContext { /// /// For the most part, other contexts are treated just like a regular `const`, so they are /// lumped into the same category. - Const, + Const { inline: bool }, } impl ConstContext { @@ -1624,7 +1624,7 @@ impl ConstContext { /// E.g. `const` or `static mut`. pub fn keyword_name(self) -> &'static str { match self { - Self::Const => "const", + Self::Const { .. } => "const", Self::Static(Mutability::Not) => "static", Self::Static(Mutability::Mut) => "static mut", Self::ConstFn => "const fn", @@ -1637,7 +1637,7 @@ impl ConstContext { impl fmt::Display for ConstContext { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - Self::Const => write!(f, "constant"), + Self::Const { .. } => write!(f, "constant"), Self::Static(_) => write!(f, "static"), Self::ConstFn => write!(f, "constant function"), } @@ -2853,13 +2853,13 @@ impl ImplicitSelfKind { #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] #[derive(HashStable_Generic)] pub enum IsAsync { - Async, + Async(Span), NotAsync, } impl IsAsync { pub fn is_async(self) -> bool { - self == IsAsync::Async + matches!(self, IsAsync::Async(_)) } } @@ -3296,7 +3296,7 @@ pub struct FnHeader { impl FnHeader { pub fn is_async(&self) -> bool { - matches!(&self.asyncness, IsAsync::Async) + matches!(&self.asyncness, IsAsync::Async(_)) } pub fn is_const(&self) -> bool { @@ -4091,10 +4091,10 @@ mod size_asserts { static_assert_size!(GenericBound<'_>, 48); static_assert_size!(Generics<'_>, 56); static_assert_size!(Impl<'_>, 80); - static_assert_size!(ImplItem<'_>, 80); - static_assert_size!(ImplItemKind<'_>, 32); - static_assert_size!(Item<'_>, 80); - static_assert_size!(ItemKind<'_>, 48); + static_assert_size!(ImplItem<'_>, 88); + static_assert_size!(ImplItemKind<'_>, 40); + static_assert_size!(Item<'_>, 88); + static_assert_size!(ItemKind<'_>, 56); static_assert_size!(Local<'_>, 64); static_assert_size!(Param<'_>, 32); static_assert_size!(Pat<'_>, 72); @@ -4105,8 +4105,8 @@ mod size_asserts { static_assert_size!(Res, 12); static_assert_size!(Stmt<'_>, 32); static_assert_size!(StmtKind<'_>, 16); - static_assert_size!(TraitItem<'_>, 80); - static_assert_size!(TraitItemKind<'_>, 40); + static_assert_size!(TraitItem<'_>, 88); + static_assert_size!(TraitItemKind<'_>, 48); static_assert_size!(Ty<'_>, 48); static_assert_size!(TyKind<'_>, 32); // tidy-alphabetical-end diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 38f19aa09ad..7be18a36d63 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -595,7 +595,7 @@ fn compare_asyncness<'tcx>( trait_m: ty::AssocItem, delay: bool, ) -> Result<(), ErrorGuaranteed> { - if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async { + if tcx.asyncness(trait_m.def_id).is_async() { match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() { ty::Alias(ty::Opaque, ..) => { // allow both `async fn foo()` and `fn foo() -> impl Future` diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index fcaefe0261b..3cd3f5bcfdd 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -11,8 +11,8 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use std::ops::Not; +use super::check_function_signature; use crate::errors; -use crate::require_same_types; pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) { match tcx.entry_fn(()) { @@ -112,7 +112,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } let main_asyncness = tcx.asyncness(main_def_id); - if let hir::IsAsync::Async = main_asyncness { + if main_asyncness.is_async() { let asyncness_span = main_fn_asyncness_span(tcx, main_def_id); tcx.sess.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span }); error = true; @@ -162,33 +162,33 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { error = true; } // now we can take the return type of the given main function - expected_return_type = main_fnsig.output(); + expected_return_type = norm_return_ty; } else { // standard () main return type - expected_return_type = ty::Binder::dummy(Ty::new_unit(tcx)); + expected_return_type = tcx.types.unit; } if error { return; } - let se_ty = Ty::new_fn_ptr( - tcx, - expected_return_type.map_bound(|expected_return_type| { - tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust) - }), - ); + let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig( + [], + expected_return_type, + false, + hir::Unsafety::Normal, + Abi::Rust, + )); - require_same_types( + check_function_signature( tcx, - &ObligationCause::new( + ObligationCause::new( main_span, main_diagnostics_def_id, ObligationCauseCode::MainFunctionType, ), - param_env, - se_ty, - Ty::new_fn_ptr(tcx, main_fnsig), + main_def_id, + expected_sig, ); } @@ -212,7 +212,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { }); error = true; } - if let hir::IsAsync::Async = sig.header.asyncness { + if sig.header.asyncness.is_async() { let span = tcx.def_span(it.owner_id); tcx.sess.emit_err(errors::StartAsync { span: span }); error = true; @@ -247,27 +247,23 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { } } - let se_ty = Ty::new_fn_ptr( - tcx, - ty::Binder::dummy(tcx.mk_fn_sig( - [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))], - tcx.types.isize, - false, - hir::Unsafety::Normal, - Abi::Rust, - )), - ); + let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig( + [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))], + tcx.types.isize, + false, + hir::Unsafety::Normal, + Abi::Rust, + )); - require_same_types( + check_function_signature( tcx, - &ObligationCause::new( + ObligationCause::new( start_span, start_def_id, ObligationCauseCode::StartFunctionType, ), - ty::ParamEnv::empty(), // start should not have any where bounds. - se_ty, - Ty::new_fn_ptr(tcx, tcx.fn_sig(start_def_id).instantiate_identity()), + start_def_id.into(), + expected_sig, ); } _ => { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index f89e2e5c25b..444103ffe8f 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -1,11 +1,11 @@ //! Type-checking for the rust-intrinsic and platform-intrinsic //! intrinsics that the compiler exposes. +use crate::check::check_function_signature; use crate::errors::{ UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction, WrongNumberOfGenericArgumentsToIntrinsic, }; -use crate::require_same_types; use hir::def_id::DefId; use rustc_errors::{struct_span_err, DiagnosticMessage}; @@ -53,15 +53,12 @@ fn equate_intrinsic_type<'tcx>( && gen_count_ok(own_counts.types, n_tps, "type") && gen_count_ok(own_counts.consts, 0, "const") { - let fty = Ty::new_fn_ptr(tcx, sig); let it_def_id = it.owner_id.def_id; - let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType); - require_same_types( + check_function_signature( tcx, - &cause, - ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env? - Ty::new_fn_ptr(tcx, tcx.fn_sig(it.owner_id).instantiate_identity()), - fty, + ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType), + it_def_id.into(), + sig, ); } } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index d8331661366..0cf3cee66b5 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -73,23 +73,31 @@ pub mod wfcheck; pub use check::check_abi; +use std::num::NonZeroU32; + use check::check_mod_item_types; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; +use rustc_infer::infer::error_reporting::ObligationCauseExt as _; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::{self, TyCtxtInferExt as _}; +use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::parse::feature_err; use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, BytePos, Span, Symbol}; +use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; -use std::num::NonZeroU32; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; +use rustc_trait_selection::traits::ObligationCtxt; use crate::errors; use crate::require_c_abi_if_c_variadic; @@ -546,3 +554,79 @@ fn bad_non_zero_sized_fields<'tcx>( pub fn potentially_plural_count(count: usize, word: &str) -> String { format!("{} {}{}", count, word, pluralize!(count)) } + +pub fn check_function_signature<'tcx>( + tcx: TyCtxt<'tcx>, + mut cause: ObligationCause<'tcx>, + fn_id: DefId, + expected_sig: ty::PolyFnSig<'tcx>, +) { + let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID); + + let param_env = ty::ParamEnv::empty(); + + let infcx = &tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(infcx); + + let actual_sig = tcx.fn_sig(fn_id).instantiate_identity(); + + let norm_cause = ObligationCause::misc(cause.span, local_id); + let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig); + + let expected_ty = Ty::new_fn_ptr(tcx, expected_sig); + let actual_ty = Ty::new_fn_ptr(tcx, actual_sig); + + match ocx.eq(&cause, param_env, expected_ty, actual_ty) { + Ok(()) => { + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors); + return; + } + } + Err(err) => { + let err_ctxt = infcx.err_ctxt(); + if fn_id.is_local() { + cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id); + } + let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]); + let mut diag = tcx.sess.create_err(failure_code); + err_ctxt.note_type_err( + &mut diag, + &cause, + None, + Some(infer::ValuePairs::Sigs(ExpectedFound { + expected: tcx.liberate_late_bound_regions(fn_id, expected_sig), + found: tcx.liberate_late_bound_regions(fn_id, actual_sig), + })), + err, + false, + false, + ); + diag.emit(); + return; + } + } + + let outlives_env = OutlivesEnvironment::new(param_env); + let _ = ocx.resolve_regions_and_report_errors(local_id, &outlives_env); + + fn extract_span_for_error_reporting<'tcx>( + tcx: TyCtxt<'tcx>, + err: TypeError<'_>, + cause: &ObligationCause<'tcx>, + fn_id: LocalDefId, + ) -> rustc_span::Span { + let mut args = { + let node = tcx.hir().expect_owner(fn_id); + let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node)); + decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span())) + }; + + match err { + TypeError::ArgumentMutability(i) + | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(), + _ => cause.span(), + } + } +} diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 6869c869603..a39cfd7b6e1 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1213,7 +1213,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { && let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id)) && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) && param.is_elided_lifetime() - && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id) + && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async() && !self.tcx.features().anonymous_lifetime_in_impl_trait { let mut diag = rustc_session::parse::feature_err( diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 957a6bb3481..0544c5ca866 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -1,7 +1,7 @@ use rustc_errors::StashKey; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem}; +use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::DUMMY_SP; @@ -74,9 +74,14 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local hidden.ty } else { + let mut parent_def_id = def_id; + while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy { + // Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031) + parent_def_id = tcx.local_parent(parent_def_id); + } let reported = tcx.sess.emit_err(UnconstrainedOpaqueType { span: tcx.def_span(def_id), - name: tcx.item_name(tcx.local_parent(def_id).to_def_id()), + name: tcx.item_name(parent_def_id.to_def_id()), what: match tcx.hir().get(scope) { _ if scope == hir::CRATE_HIR_ID => "module", Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module", diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index ef788935efb..03963925d3d 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -99,7 +99,6 @@ use rustc_errors::ErrorGuaranteed; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; -use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::middle; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -107,8 +106,7 @@ use rustc_middle::util; use rustc_session::parse::feature_err; use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt}; +use rustc_trait_selection::traits; use astconv::{AstConv, OnlySelfBounds}; use bounds::Bounds; @@ -151,28 +149,6 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi tcx.sess.emit_err(errors::VariadicFunctionCompatibleConvention { span, conventions }); } -fn require_same_types<'tcx>( - tcx: TyCtxt<'tcx>, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - expected: Ty<'tcx>, - actual: Ty<'tcx>, -) { - let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); - match ocx.eq(cause, param_env, expected, actual) { - Ok(()) => { - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); - } - } - Err(err) => { - infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit(); - } - } -} - pub fn provide(providers: &mut Providers) { collect::provide(providers); coherence::provide(providers); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 89efdc269c4..8587b009f25 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2304,7 +2304,7 @@ impl<'a> State<'a> { match header.asyncness { hir::IsAsync::NotAsync => {} - hir::IsAsync::Async => self.word_nbsp("async"), + hir::IsAsync::Async(_) => self.word_nbsp("async"), } self.print_unsafety(header.unsafety); diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 921a5f5154a..9950a226333 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -83,16 +83,6 @@ hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*cons hir_typeck_invalid_callee = expected function, found {$ty} -hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` -hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item -hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count} - -hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect - .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` - -hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect - .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` - hir_typeck_lossy_provenance_int2ptr = strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}` .suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index b39919ece71..f2c58ee2702 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -788,7 +788,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let effect = match const_context { _ if host_always_on => tcx.consts.true_, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_, + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => { + tcx.consts.false_ + } Some(hir::ConstContext::ConstFn) => { let args = ty::GenericArgs::identity_for_item(tcx, context); args.host_effect_param().expect("ConstContext::Maybe must have host effect param") diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 1fc1e5aca2b..041cc1abd54 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -1,7 +1,6 @@ +use std::cell::RefCell; + use crate::coercion::CoerceMany; -use crate::errors::{ - LangStartIncorrectNumberArgs, LangStartIncorrectParam, LangStartIncorrectRetTy, -}; use crate::gather_locals::GatherLocalsVisitor; use crate::FnCtxt; use crate::GeneratorTypes; @@ -9,14 +8,15 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir_analysis::check::fn_maybe_err; +use rustc_hir_analysis::check::{check_function_signature, fn_maybe_err}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::ty::{self, Binder, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; -use std::cell::RefCell; +use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; /// Helper used for fns and closures. Does the grungy work of checking a function /// body and returns the function context used for that purpose, since in the case of a fn item @@ -166,52 +166,17 @@ pub(super) fn check_fn<'a, 'tcx>( if let Some(panic_impl_did) = tcx.lang_items().panic_impl() && panic_impl_did == fn_def_id.to_def_id() { - check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty); + check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig); } if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == fn_def_id.to_def_id() { - check_lang_start_fn(tcx, fn_sig, decl, fn_def_id); + check_lang_start_fn(tcx, fn_sig, fn_def_id); } gen_ty } -fn check_panic_info_fn( - tcx: TyCtxt<'_>, - fn_id: LocalDefId, - fn_sig: ty::FnSig<'_>, - decl: &hir::FnDecl<'_>, - declared_ret_ty: Ty<'_>, -) { - let Some(panic_info_did) = tcx.lang_items().panic_info() else { - tcx.sess.err("language item required, but not found: `panic_info`"); - return; - }; - - if *declared_ret_ty.kind() != ty::Never { - tcx.sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - if inputs.len() != 1 { - tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument"); - return; - } - - let arg_is_panic_info = match *inputs[0].kind() { - ty::Ref(region, ty, mutbl) => match *ty.kind() { - ty::Adt(ref adt, _) => { - adt.did() == panic_info_did && mutbl.is_not() && !region.is_static() - } - _ => false, - }, - _ => false, - }; - - if !arg_is_panic_info { - tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); - } - +fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) { let DefKind::Fn = tcx.def_kind(fn_id) else { let span = tcx.def_span(fn_id); tcx.sess.span_err(span, "should be a function"); @@ -227,125 +192,87 @@ fn check_panic_info_fn( let span = tcx.def_span(fn_id); tcx.sess.span_err(span, "should have no const parameters"); } -} - -fn check_lang_start_fn<'tcx>( - tcx: TyCtxt<'tcx>, - fn_sig: ty::FnSig<'tcx>, - decl: &'tcx hir::FnDecl<'tcx>, - def_id: LocalDefId, -) { - let inputs = fn_sig.inputs(); - - let arg_count = inputs.len(); - if arg_count != 4 { - tcx.sess.emit_err(LangStartIncorrectNumberArgs { - params_span: tcx.def_span(def_id), - found_param_count: arg_count, - }); - } - // only check args if they should exist by checking the count - // note: this does not handle args being shifted or their order swapped very nicely - // but it's a lang item, users shouldn't frequently encounter this - - // first arg is `main: fn() -> T` - if let Some(&main_arg) = inputs.get(0) { - // make a Ty for the generic on the fn for diagnostics - // FIXME: make the lang item generic checks check for the right generic *kind* - // for example `start`'s generic should be a type parameter - let generics = tcx.generics_of(def_id); - let fn_generic = generics.param_at(0, tcx); - let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name); - let expected_fn_sig = - tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust); - let expected_ty = Ty::new_fn_ptr(tcx, Binder::dummy(expected_fn_sig)); - - // we emit the same error to suggest changing the arg no matter what's wrong with the arg - let emit_main_fn_arg_err = || { - tcx.sess.emit_err(LangStartIncorrectParam { - param_span: decl.inputs[0].span, - param_num: 1, - expected_ty: expected_ty, - found_ty: main_arg, - }); - }; - - if let ty::FnPtr(main_fn_sig) = main_arg.kind() { - let main_fn_inputs = main_fn_sig.inputs(); - if main_fn_inputs.iter().count() != 0 { - emit_main_fn_arg_err(); - } - - let output = main_fn_sig.output(); - output.map_bound(|ret_ty| { - // if the output ty is a generic, it's probably the right one - if !matches!(ret_ty.kind(), ty::Param(_)) { - emit_main_fn_arg_err(); - } - }); - } else { - emit_main_fn_arg_err(); - } - } - - // second arg is isize - if let Some(&argc_arg) = inputs.get(1) { - if argc_arg != tcx.types.isize { - tcx.sess.emit_err(LangStartIncorrectParam { - param_span: decl.inputs[1].span, - param_num: 2, - expected_ty: tcx.types.isize, - found_ty: argc_arg, - }); - } - } - - // third arg is `*const *const u8` - if let Some(&argv_arg) = inputs.get(2) { - let mut argv_is_okay = false; - if let ty::RawPtr(outer_ptr) = argv_arg.kind() { - if outer_ptr.mutbl.is_not() { - if let ty::RawPtr(inner_ptr) = outer_ptr.ty.kind() { - if inner_ptr.mutbl.is_not() && inner_ptr.ty == tcx.types.u8 { - argv_is_okay = true; - } - } - } - } - - if !argv_is_okay { - let inner_ptr_ty = - Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 }); - let expected_ty = - Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty }); - tcx.sess.emit_err(LangStartIncorrectParam { - param_span: decl.inputs[2].span, - param_num: 3, - expected_ty, - found_ty: argv_arg, - }); - } - } + let Some(panic_info_did) = tcx.lang_items().panic_info() else { + tcx.sess.err("language item required, but not found: `panic_info`"); + return; + }; - // fourth arg is `sigpipe: u8` - if let Some(&sigpipe_arg) = inputs.get(3) { - if sigpipe_arg != tcx.types.u8 { - tcx.sess.emit_err(LangStartIncorrectParam { - param_span: decl.inputs[3].span, - param_num: 4, - expected_ty: tcx.types.u8, - found_ty: sigpipe_arg, - }); - } - } + // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` + let panic_info_ty = tcx.type_of(panic_info_did).instantiate( + tcx, + &[ty::GenericArg::from(ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon(None) }, + ))], + ); + let panic_info_ref_ty = Ty::new_imm_ref( + tcx, + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }, + ), + panic_info_ty, + ); + + let bounds = tcx.mk_bound_variable_kinds(&[ + ty::BoundVariableKind::Region(ty::BrAnon(None)), + ty::BoundVariableKind::Region(ty::BrAnon(None)), + ]); + let expected_sig = ty::Binder::bind_with_vars( + tcx.mk_fn_sig([panic_info_ref_ty], tcx.types.never, false, fn_sig.unsafety, Abi::Rust), + bounds, + ); + + check_function_signature( + tcx, + ObligationCause::new( + tcx.def_span(fn_id), + fn_id, + ObligationCauseCode::LangFunctionType(sym::panic_impl), + ), + fn_id.into(), + expected_sig, + ); +} - // output type is isize - if fn_sig.output() != tcx.types.isize { - tcx.sess.emit_err(LangStartIncorrectRetTy { - ret_span: decl.output.span(), - expected_ty: tcx.types.isize, - found_ty: fn_sig.output(), - }); - } +fn check_lang_start_fn<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: ty::FnSig<'tcx>, def_id: LocalDefId) { + // build type `fn(main: fn() -> T, argc: isize, argv: *const *const u8, sigpipe: u8)` + + // make a Ty for the generic on the fn for diagnostics + // FIXME: make the lang item generic checks check for the right generic *kind* + // for example `start`'s generic should be a type parameter + let generics = tcx.generics_of(def_id); + let fn_generic = generics.param_at(0, tcx); + let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name); + let main_fn_ty = Ty::new_fn_ptr( + tcx, + Binder::dummy(tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust)), + ); + + let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig( + [ + main_fn_ty, + tcx.types.isize, + Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8)), + tcx.types.u8, + ], + tcx.types.isize, + false, + fn_sig.unsafety, + Abi::Rust, + )); + + check_function_signature( + tcx, + ObligationCause::new( + tcx.def_span(def_id), + def_id, + ObligationCauseCode::LangFunctionType(sym::start), + ), + def_id.into(), + expected_sig, + ); } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 7152585d440..1526988fbd9 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -236,39 +236,6 @@ impl AddToDiagnostic for TypeMismatchFruTypo { } } -#[derive(Diagnostic)] -#[diag(hir_typeck_lang_start_incorrect_number_params)] -#[note(hir_typeck_lang_start_incorrect_number_params_note_expected_count)] -#[note(hir_typeck_lang_start_expected_sig_note)] -pub struct LangStartIncorrectNumberArgs { - #[primary_span] - pub params_span: Span, - pub found_param_count: usize, -} - -#[derive(Diagnostic)] -#[diag(hir_typeck_lang_start_incorrect_param)] -pub struct LangStartIncorrectParam<'tcx> { - #[primary_span] - #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")] - pub param_span: Span, - - pub param_num: usize, - pub expected_ty: Ty<'tcx>, - pub found_ty: Ty<'tcx>, -} - -#[derive(Diagnostic)] -#[diag(hir_typeck_lang_start_incorrect_ret_ty)] -pub struct LangStartIncorrectRetTy<'tcx> { - #[primary_span] - #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")] - pub ret_span: Span, - - pub expected_ty: Ty<'tcx>, - pub found_ty: Ty<'tcx>, -} - #[derive(LintDiagnostic)] #[diag(hir_typeck_lossy_provenance_int2ptr)] #[help] diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 70d1dad8a6f..4ad14ce3059 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -525,8 +525,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, }; - if let ty::FnDef(did, ..) = *ty.kind() { + if let ty::FnDef(did, callee_args) = *ty.kind() { let fn_sig = ty.fn_sig(tcx); + + // HACK: whenever we get a FnDef in a non-const context, enforce effects to get the + // default `host = true` to avoid inference errors later. + if tcx.hir().body_const_context(self.body_id).is_none() { + self.enforce_context_effects(expr.hir_id, qpath.span(), did, callee_args); + } if tcx.fn_sig(did).skip_binder().abi() == RustIntrinsic && tcx.item_name(did) == sym::transmute { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 4def7867384..37ea94d821e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -273,11 +273,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // This check is here because there is currently no way to express a trait bound for `FnDef` types only. if is_const_eval_select && (1..=2).contains(&idx) { - if let ty::FnDef(def_id, _) = checked_ty.kind() { - if idx == 1 && !self.tcx.is_const_fn_raw(*def_id) { - self.tcx - .sess - .emit_err(errors::ConstSelectMustBeConst { span: provided_arg.span }); + if let ty::FnDef(def_id, args) = *checked_ty.kind() { + if idx == 1 { + if !self.tcx.is_const_fn_raw(def_id) { + self.tcx.sess.emit_err(errors::ConstSelectMustBeConst { + span: provided_arg.span, + }); + } else { + self.enforce_context_effects( + provided_arg.hir_id, + provided_arg.span, + def_id, + args, + ) + } } } else { self.tcx.sess.emit_err(errors::ConstSelectMustBeFn { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index d2a53ee8b5e..41f815a812a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -987,10 +987,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bound_vars = self.tcx.late_bound_vars(fn_id); let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); let ty = match self.tcx.asyncness(fn_id.owner) { - hir::IsAsync::Async => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { + ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { span_bug!(fn_decl.output.span(), "failed to get output type of async function") }), - hir::IsAsync::NotAsync => ty, + ty::Asyncness::No => ty, }; let ty = self.normalize(expr.span, ty); if self.can_coerce(found, ty) { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 603681bbc99..2fe41c1197f 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Type only exists for constants and statics, not functions. match self.tcx.hir().body_owner_kind(item_def_id) { - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { + hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => { let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id); wbcx.visit_node_id(body.value.span, item_hir_id); } diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 5e7ae3ecdb8..1b160eca92d 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -42,7 +42,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::dep_graph::{ - DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter, + dep_kinds, DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter, }; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; @@ -129,7 +129,7 @@ impl<'tcx> IfThisChanged<'tcx> { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { None => { - DepNode::from_def_path_hash(self.tcx, def_path_hash, DepKind::hir_owner) + DepNode::from_def_path_hash(self.tcx, def_path_hash, dep_kinds::hir_owner) } Some(n) => { match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 8d67f692568..25e694fa1c1 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -3,7 +3,7 @@ use crate::errors; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::unord::UnordMap; -use rustc_middle::dep_graph::{SerializedDepGraph, WorkProductMap}; +use rustc_middle::dep_graph::{DepsType, SerializedDepGraph, WorkProductMap}; use rustc_middle::query::on_disk_cache::OnDiskCache; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::Decodable; @@ -208,7 +208,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { return LoadResult::DataOutOfDate; } - let dep_graph = SerializedDepGraph::decode(&mut decoder); + let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder); LoadResult::Ok { data: (dep_graph, prev_work_products) } } diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 4d0e7706367..46558997f72 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -198,6 +198,10 @@ infer_nothing = {""} infer_oc_cant_coerce = cannot coerce intrinsics to function pointers infer_oc_closure_selfref = closure/generator type that references itself infer_oc_const_compat = const not compatible with trait +infer_oc_fn_lang_correct_type = {$lang_item_name -> + [panic_impl] `#[panic_handler]` + *[lang_item_name] lang item `{$lang_item_name}` + } function has wrong type infer_oc_fn_main_correct_type = `main` function has wrong type infer_oc_fn_start_correct_type = `#[start]` function has wrong type infer_oc_generic = mismatched types @@ -337,6 +341,7 @@ infer_subtype = ...so that the {$requirement -> [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type [fn_start_correct_type] `#[start]` function has the correct type + [fn_lang_correct_type] lang item function has the correct type [intrinsic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type *[other] types are compatible @@ -350,6 +355,7 @@ infer_subtype_2 = ...so that {$requirement -> [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type [fn_start_correct_type] `#[start]` function has the correct type + [fn_lang_correct_type] lang item function has the correct type [intrinsic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type *[other] types are compatible diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index a7e045e1e89..38910e45ecc 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1463,6 +1463,14 @@ pub enum ObligationCauseFailureCode { #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, + #[diag(infer_oc_fn_lang_correct_type, code = "E0308")] + FnLangCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + lang_item_name: Symbol, + }, #[diag(infer_oc_intrinsic_correct_type, code = "E0308")] IntrinsicCorrectType { #[primary_span] diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b8701d3d3ef..1beb13cb94c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2927,6 +2927,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { | IfExpression { .. } | LetElse | StartFunctionType + | LangFunctionType(_) | IntrinsicType | MethodReceiver => Error0308, @@ -2971,6 +2972,9 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags }, MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span }, StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }, + &LangFunctionType(lang_item_name) => { + ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name } + } IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags }, MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags }, @@ -3006,6 +3010,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { IfExpressionWithNoElse => "`if` missing an `else` returns `()`", MainFunctionType => "`main` function has the correct type", StartFunctionType => "`#[start]` function has the correct type", + LangFunctionType(_) => "lang item function has the correct type", IntrinsicType => "intrinsic has the correct type", MethodReceiver => "method receiver has the correct type", _ => "types are compatible", @@ -3028,6 +3033,7 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> { IfExpressionWithNoElse => "no_else", MainFunctionType => "fn_main_correct_type", StartFunctionType => "fn_start_correct_type", + LangFunctionType(_) => "fn_lang_correct_type", IntrinsicType => "intrinsic_correct_type", MethodReceiver => "method_correct_type", _ => "other", diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index bc6d7c20997..45b1aeb4a5c 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -10,8 +10,10 @@ //! origin crate when the `TyCtxt` is not present in TLS. use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS}; -use rustc_middle::dep_graph::TaskDepsRef; +use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef}; use rustc_middle::ty::tls; +use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug; +use rustc_query_system::dep_graph::{DepContext, DepKind, DepNode}; use std::fmt; fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { @@ -59,10 +61,49 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> write!(f, ")") } +/// This is a callback from `rustc_query_system` as it cannot access the implicit state +/// in `rustc_middle` otherwise. +pub fn dep_kind_debug(kind: DepKind, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + write!(f, "{}", tcx.dep_kind_info(kind).name) + } else { + default_dep_kind_debug(kind, f) + } + }) +} + +/// This is a callback from `rustc_query_system` as it cannot access the implicit state +/// in `rustc_middle` otherwise. +pub fn dep_node_debug(node: DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}(", node.kind)?; + + tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_id) = node.extract_def_id(tcx) { + write!(f, "{}", tcx.def_path_debug_str(def_id))?; + } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(node) { + write!(f, "{s}")?; + } else { + write!(f, "{}", node.hash)?; + } + } else { + write!(f, "{}", node.hash)?; + } + Ok(()) + })?; + + write!(f, ")") +} + /// Sets up the callbacks in prior crates which we want to refer to the /// TyCtxt in. pub fn setup_callbacks() { rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_))); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + rustc_query_system::dep_graph::dep_node::DEP_KIND_DEBUG + .swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG + .swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _)); } diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index d0967ba5644..814991cd8c9 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -34,8 +34,8 @@ declare_lint! { Warn, "detects calling `into_iter` on arrays in Rust 2015 and 2018", @future_incompatible = FutureIncompatibleInfo { - reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>", reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021), + reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>", }; } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index de228bdb850..4f6b79d9aee 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -41,7 +41,6 @@ use crate::{ }, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, }; -use hir::IsAsync; use rustc_ast::attr; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; @@ -845,8 +844,8 @@ declare_lint! { Warn, "detects anonymous parameters", @future_incompatible = FutureIncompatibleInfo { - reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>", reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018), + reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>", }; } @@ -1294,7 +1293,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { span: Span, def_id: LocalDefId, ) { - if fn_kind.asyncness() == IsAsync::Async + if fn_kind.asyncness().is_async() && !cx.tcx.features().async_fn_track_caller // Now, check if the function has the `#[track_caller]` attribute && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) @@ -1670,8 +1669,8 @@ declare_lint! { Warn, "`...` range patterns are deprecated", @future_incompatible = FutureIncompatibleInfo { - reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>", reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), + reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>", }; } @@ -1805,8 +1804,8 @@ declare_lint! { Allow, "detects edition keywords being used as an identifier", @future_incompatible = FutureIncompatibleInfo { - reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>", reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018), + reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>", }; } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 7a336a8f694..460d54739a2 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1315,6 +1315,54 @@ impl<'tcx> LateContext<'tcx> { tcx.try_normalize_erasing_regions(self.param_env, proj).ok() }) } + + /// If the given expression is a local binding, find the initializer expression. + /// If that initializer expression is another local or **outside** (`const`/`static`) + /// binding, find its initializer again. + /// + /// This process repeats as long as possible (but usually no more than once). + /// Type-check adjustments are not taken in account in this function. + /// + /// Examples: + /// ``` + /// const ABC: i32 = 1; + /// // ^ output + /// let def = ABC; + /// dbg!(def); + /// // ^^^ input + /// + /// // or... + /// let abc = 1; + /// let def = abc + 2; + /// // ^^^^^^^ output + /// dbg!(def); + /// // ^^^ input + /// ``` + pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> { + expr = expr.peel_blocks(); + + while let hir::ExprKind::Path(ref qpath) = expr.kind + && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) { + Res::Local(hir_id) => self.tcx.hir().find_parent(hir_id), + Res::Def(_, def_id) => self.tcx.hir().get_if_local(def_id), + _ => None, + } + && let Some(init) = match parent_node { + hir::Node::Expr(expr) => Some(expr), + hir::Node::Local(hir::Local { init, .. }) => *init, + hir::Node::Item(item) => match item.kind { + hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => { + Some(self.tcx.hir().body(body_id).value) + } + _ => None + } + _ => None + } + { + expr = init.peel_blocks(); + } + expr + } } impl<'tcx> abi::HasDataLayout for LateContext<'tcx> { diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index 851c6493daf..9be2edf8453 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -5,6 +5,7 @@ use crate::{ use rustc_hir as hir; use rustc_middle::{traits::util::supertraits, ty}; +use rustc_session::lint::FutureIncompatibilityReason; use rustc_span::sym; declare_lint! { @@ -48,6 +49,7 @@ declare_lint! { Warn, "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>", }; } diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index 3291286ad67..1841e7c85a8 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -1,6 +1,6 @@ use std::str::Utf8Error; -use rustc_ast::{BorrowKind, LitKind}; +use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -11,7 +11,7 @@ use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { /// The `invalid_from_utf8_unchecked` lint checks for calls to /// `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut` - /// with an invalid UTF-8 literal. + /// with a known invalid UTF-8 value. /// /// ### Example /// @@ -36,7 +36,7 @@ declare_lint! { declare_lint! { /// The `invalid_from_utf8` lint checks for calls to /// `std::str::from_utf8` and `std::str::from_utf8_mut` - /// with an invalid UTF-8 literal. + /// with a known invalid UTF-8 value. /// /// ### Example /// @@ -67,8 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { && [sym::str_from_utf8, sym::str_from_utf8_mut, sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) { - let lint = |utf8_error: Utf8Error| { - let label = arg.span; + let lint = |label, utf8_error: Utf8Error| { let method = diag_item.as_str().strip_prefix("str_").unwrap(); let method = format!("std::str::{method}"); let valid_up_to = utf8_error.valid_up_to(); @@ -78,22 +77,26 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 }, expr.span, if is_unchecked_variant { - InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label } + InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label } } else { - InvalidFromUtf8Diag::Checked { method, valid_up_to, label } + InvalidFromUtf8Diag::Checked { method, valid_up_to, label } } ) }; - match &arg.kind { + let mut init = cx.expr_or_init(arg); + while let ExprKind::AddrOf(.., inner) = init.kind { + init = cx.expr_or_init(inner); + } + match init.kind { ExprKind::Lit(Spanned { node: lit, .. }) => { if let LitKind::ByteStr(bytes, _) = &lit && let Err(utf8_error) = std::str::from_utf8(bytes) { - lint(utf8_error); + lint(init.span, utf8_error); } }, - ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => { + ExprKind::Array(args) => { let elements = args.iter().map(|e|{ match &e.kind { ExprKind::Lit(Spanned { node: lit, .. }) => match lit { @@ -108,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { if let Some(elements) = elements && let Err(utf8_error) = std::str::from_utf8(&elements) { - lint(utf8_error); + lint(init.span, utf8_error); } } _ => {} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 860366fdd61..1951db49e91 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -39,6 +39,7 @@ declare_lint! { Warn, "applying forbid to lint-groups", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #81670 <https://github.com/rust-lang/rust/issues/81670>", }; } @@ -74,6 +75,7 @@ declare_lint! { Deny, "ill-formed attribute inputs that were previously accepted and used in practice", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>", }; crate_level_only @@ -110,6 +112,7 @@ declare_lint! { Deny, "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #68585 <https://github.com/rust-lang/rust/issues/68585>", }; } @@ -1016,8 +1019,8 @@ declare_lint! { Deny, "raw pointers must be aligned before dereferencing", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #68585 <https://github.com/rust-lang/rust/issues/104616>", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } @@ -1096,6 +1099,7 @@ declare_lint! { Deny, "detect public re-exports of private extern crates", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>", }; } @@ -1125,6 +1129,7 @@ declare_lint! { Deny, "type parameter default erroneously allowed in invalid location", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>", }; } @@ -1267,6 +1272,7 @@ declare_lint! { Deny, "patterns in functions without body were erroneously allowed", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>", }; } @@ -1310,6 +1316,7 @@ declare_lint! { Deny, "detects missing fragment specifiers in unused `macro_rules!` patterns", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>", }; } @@ -1351,6 +1358,7 @@ declare_lint! { Warn, "detects generic lifetime arguments in path segments with late bound lifetime parameters", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>", }; } @@ -1386,8 +1394,8 @@ declare_lint! { Deny, "trait-object types were treated as different depending on marker-trait order", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } @@ -1426,6 +1434,7 @@ declare_lint! { Warn, "distinct impls distinguished only by the leak-check code", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #56105 <https://github.com/rust-lang/rust/issues/56105>", }; } @@ -1617,8 +1626,8 @@ declare_lint! { Warn, "raw pointer to an inference variable", @future_incompatible = FutureIncompatibleInfo { - reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>", reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018), + reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>", }; } @@ -1685,8 +1694,8 @@ declare_lint! { Warn, "suggest using `dyn Trait` for trait objects", @future_incompatible = FutureIncompatibleInfo { - reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>", reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), + reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>", }; } @@ -1740,8 +1749,8 @@ declare_lint! { "fully qualified paths that start with a module name \ instead of `crate`, `self`, or an extern crate name", @future_incompatible = FutureIncompatibleInfo { - reference: "issue #53130 <https://github.com/rust-lang/rust/issues/53130>", reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018), + reference: "issue #53130 <https://github.com/rust-lang/rust/issues/53130>", }; } @@ -1789,6 +1798,7 @@ declare_lint! { Warn, "floating-point literals cannot be used in patterns", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>", }; } @@ -1939,6 +1949,7 @@ declare_lint! { Warn, "checks the object safety of where clauses", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>", }; } @@ -2005,8 +2016,8 @@ declare_lint! { Deny, "detects proc macro derives using inaccessible names from parent modules", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } @@ -2108,6 +2119,7 @@ declare_lint! { "macro-expanded `macro_export` macros from the current crate \ cannot be referred to by absolute paths", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>", }; crate_level_only @@ -2199,6 +2211,7 @@ declare_lint! { Warn, "constant used in pattern contains value of non-structural-match type in a field or a variant", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>", }; } @@ -2253,6 +2266,7 @@ declare_lint! { Allow, "pointers are not structural-match", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #62411 <https://github.com/rust-lang/rust/issues/70861>", }; } @@ -2291,6 +2305,7 @@ declare_lint! { "constant used in pattern of non-structural-match type and the constant's initializer \ expression contains values of non-structural-match types", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #73448 <https://github.com/rust-lang/rust/issues/73448>", }; } @@ -2348,6 +2363,7 @@ declare_lint! { Deny, "ambiguous associated items", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #57644 <https://github.com/rust-lang/rust/issues/57644>", }; } @@ -2389,6 +2405,7 @@ declare_lint! { Deny, "a feature gate that doesn't break dependent crates", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #64266 <https://github.com/rust-lang/rust/issues/64266>", }; } @@ -2617,8 +2634,8 @@ declare_lint! { Deny, "a C-like enum implementing Drop is cast", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #73333 <https://github.com/rust-lang/rust/issues/73333>", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } @@ -2747,6 +2764,7 @@ declare_lint! { Warn, "detects a generic constant is used in a type without a emitting a warning", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #76200 <https://github.com/rust-lang/rust/issues/76200>", }; } @@ -2805,6 +2823,7 @@ declare_lint! { Warn, "uninhabited static", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #74840 <https://github.com/rust-lang/rust/issues/74840>", }; } @@ -2975,8 +2994,8 @@ declare_lint! { Warn, "trailing semicolon in macro body used as expression", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #79813 <https://github.com/rust-lang/rust/issues/79813>", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } @@ -3022,6 +3041,7 @@ declare_lint! { Warn, "detects derive helper attributes that are used before they are introduced", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #79202 <https://github.com/rust-lang/rust/issues/79202>", }; } @@ -3090,6 +3110,7 @@ declare_lint! { Deny, "detects usage of `#![cfg_attr(..., crate_type/crate_name = \"...\")]`", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #91632 <https://github.com/rust-lang/rust/issues/91632>", }; } @@ -3181,6 +3202,7 @@ declare_lint! { Warn, "transparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #78586 <https://github.com/rust-lang/rust/issues/78586>", }; } @@ -3231,6 +3253,7 @@ declare_lint! { Warn, "unstable syntax can change at any point in the future, causing a hard error!", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #65860 <https://github.com/rust-lang/rust/issues/65860>", }; } @@ -3662,6 +3685,7 @@ declare_lint! { Warn, "detects invalid `#[doc(...)]` attributes", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #82730 <https://github.com/rust-lang/rust/issues/82730>", }; } @@ -3708,8 +3732,8 @@ declare_lint! { Deny, "detects usage of old versions of certain proc-macro crates", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } @@ -3747,8 +3771,8 @@ declare_lint! { Allow, "detects usage of old versions of or-patterns", @future_incompatible = FutureIncompatibleInfo { - reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>", reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), + reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>", }; } @@ -3796,8 +3820,8 @@ declare_lint! { "detects the usage of trait methods which are ambiguous with traits added to the \ prelude in future editions", @future_incompatible = FutureIncompatibleInfo { - reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>", reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), + reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>", }; } @@ -3833,8 +3857,8 @@ declare_lint! { Allow, "identifiers that will be parsed as a prefix in Rust 2021", @future_incompatible = FutureIncompatibleInfo { - reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>", reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), + reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>", }; crate_level_only } @@ -3881,6 +3905,7 @@ declare_lint! { Warn, "use of unsupported calling convention", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #87678 <https://github.com/rust-lang/rust/issues/87678>", }; } @@ -4221,8 +4246,8 @@ declare_lint! { Deny, "impl method assumes more implied bounds than its corresponding trait method", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } @@ -4253,8 +4278,8 @@ declare_lint! { Warn, "`[u8]` or `str` used in a packed struct with `derive`", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; report_in_external_macro } @@ -4415,6 +4440,7 @@ declare_lint! { "impls that are not considered to overlap may be considered to \ overlap in the future", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #114040 <https://github.com/rust-lang/rust/issues/114040>", }; } @@ -4483,7 +4509,7 @@ declare_lint! { Warn, "detects certain glob imports that require reporting an ambiguity error", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #114095 <https://github.com/rust-lang/rust/issues/114095>", }; } @@ -4568,7 +4594,7 @@ declare_lint! { Warn, "elided lifetimes cannot be used in associated constants in impls", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, reference: "issue #115010 <https://github.com/rust-lang/rust/issues/115010>", }; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index ef2f7940477..84e7ecb0b88 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -347,12 +347,18 @@ pub struct FutureIncompatibleInfo { /// The reason for future incompatibility #[derive(Copy, Clone, Debug)] pub enum FutureIncompatibilityReason { - /// This will be an error in a future release - /// for all editions - FutureReleaseError, + /// This will be an error in a future release for all editions + /// + /// This will *not* show up in cargo's future breakage report. + /// The warning will hence only be seen in local crates, not in dependencies. + FutureReleaseErrorDontReportInDeps, /// This will be an error in a future release, and /// Cargo should create a report even for dependencies - FutureReleaseErrorReportNow, + /// + /// This is the *only* reason that will make future incompatibility warnings show up in cargo's + /// reports. All other future incompatibility warnings are not visible when they occur in a + /// dependency. + FutureReleaseErrorReportInDeps, /// Code that changes meaning in some way in a /// future release. FutureReleaseSemanticsChange, @@ -380,7 +386,7 @@ impl FutureIncompatibleInfo { pub const fn default_fields_for_macro() -> Self { FutureIncompatibleInfo { reference: "", - reason: FutureIncompatibilityReason::FutureReleaseError, + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, explain_reason: true, } } @@ -718,7 +724,10 @@ macro_rules! declare_lint { ); ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, $(@feature_gate = $gate:expr;)? - $(@future_incompatible = FutureIncompatibleInfo { $($field:ident : $val:expr),* $(,)* }; )? + $(@future_incompatible = FutureIncompatibleInfo { + reason: $reason:expr, + $($field:ident : $val:expr),* $(,)* + }; )? $(@edition $lint_edition:ident => $edition_level:ident;)? $($v:ident),*) => ( $(#[$attr])* @@ -730,6 +739,7 @@ macro_rules! declare_lint { $($v: true,)* $(feature_gate: Some($gate),)? $(future_incompatible: Some($crate::FutureIncompatibleInfo { + reason: $reason, $($field: $val,)* ..$crate::FutureIncompatibleInfo::default_fields_for_macro() }),)? diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index f964a8c76c0..e8c2fe5d178 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -126,8 +126,8 @@ macro_rules! provide_one { // External query providers call `crate_hash` in order to register a dependency // on the crate metadata. The exception is `crate_hash` itself, which obviously // doesn't need to do this (and can't, as it would cause a query cycle). - use rustc_middle::dep_graph::DepKind; - if DepKind::$name != DepKind::crate_hash && $tcx.dep_graph.is_fully_enabled() { + use rustc_middle::dep_graph::dep_kinds; + if dep_kinds::$name != dep_kinds::crate_hash && $tcx.dep_graph.is_fully_enabled() { $tcx.ensure().crate_hash($def_id.krate); } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 71269779d42..f2875bb11b1 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -439,7 +439,7 @@ define_tables! { coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>, mir_const_qualif: Table<DefIndex, LazyValue<mir::ConstQualifs>>, rendered_const: Table<DefIndex, LazyValue<String>>, - asyncness: Table<DefIndex, hir::IsAsync>, + asyncness: Table<DefIndex, ty::Asyncness>, fn_arg_names: Table<DefIndex, LazyArray<Ident>>, generator_kind: Table<DefIndex, LazyValue<hir::GeneratorKind>>, trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 35987072ed6..d105dab4814 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -205,9 +205,9 @@ fixed_size_enum! { } fixed_size_enum! { - hir::IsAsync { - ( NotAsync ) - ( Async ) + ty::Asyncness { + ( Yes ) + ( No ) } } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 78a0f82db13..39d82c489d5 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -65,9 +65,9 @@ use rustc_hir::definitions::DefPathHash; use rustc_hir::{HirId, ItemLocalId, OwnerId}; use rustc_query_system::dep_graph::FingerprintStyle; use rustc_span::symbol::Symbol; -use std::hash::Hash; -pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; +pub use rustc_query_system::dep_graph::dep_node::DepKind; +pub use rustc_query_system::dep_graph::{DepContext, DepNode, DepNodeParams}; macro_rules! define_dep_nodes { ( @@ -84,55 +84,39 @@ macro_rules! define_dep_nodes { // encoding. The derived Encodable/Decodable uses leb128 encoding which is // dense when only considering this enum. But DepKind is encoded in a larger // struct, and there we can take advantage of the unused bits in the u16. - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[allow(non_camel_case_types)] - #[repr(u16)] - pub enum DepKind { + #[repr(u16)] // Must be kept in sync with the inner type of `DepKind`. + enum DepKindDefs { $( $( #[$attr] )* $variant),* } - impl DepKind { - // This const implements two things: A bounds check so that we can decode - // a DepKind from a u16 with just one check, and a const check that the - // discriminants of the variants have been assigned consecutively from 0 - // so that just the one comparison suffices to check that the u16 can be - // transmuted to a DepKind. - pub const VARIANTS: u16 = { - let deps: &[DepKind] = &[$(DepKind::$variant,)*]; - let mut i = 0; - while i < deps.len() { - if i as u16 != deps[i] as u16 { - panic!(); - } - i += 1; - } - deps.len() as u16 - }; - } + #[allow(non_upper_case_globals)] + pub mod dep_kinds { + use super::*; - impl<S: rustc_serialize::Encoder> rustc_serialize::Encodable<S> for DepKind { - #[inline] - fn encode(&self, s: &mut S) { - s.emit_u16(*self as u16); - } + $( + // The `as u16` cast must be kept in sync with the inner type of `DepKind`. + pub const $variant: DepKind = DepKind::new(DepKindDefs::$variant as u16); + )* } - impl<D: rustc_serialize::Decoder> rustc_serialize::Decodable<D> for DepKind { - #[inline] - fn decode(d: &mut D) -> DepKind { - let discrim = d.read_u16(); - assert!(discrim < DepKind::VARIANTS); - // SAFETY: DepKind::VARIANTS checks that the discriminant values permit - // this one check to soundly guard the transmute. - unsafe { - std::mem::transmute::<u16, DepKind>(discrim) + // This checks that the discriminants of the variants have been assigned consecutively + // from 0 so that they can be used as a dense index. + pub const DEP_KIND_VARIANTS: u16 = { + let deps = &[$(dep_kinds::$variant,)*]; + let mut i = 0; + while i < deps.len() { + if i != deps[i].as_usize() { + panic!(); } + i += 1; } - } + deps.len() as u16 + }; pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> { match label { - $(stringify!($variant) => Ok(DepKind::$variant),)* + $(stringify!($variant) => Ok(dep_kinds::$variant),)* _ => Err(()), } } @@ -158,12 +142,10 @@ rustc_query_append!(define_dep_nodes![ [] fn CompileMonoItem() -> (), ]); -static_assert_size!(DepKind, 2); - // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. // Be very careful changing this type signature! pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode { - DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name) + DepNode::construct(tcx, dep_kinds::CompileCodegenUnit, &name) } // WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys. @@ -172,20 +154,9 @@ pub(crate) fn make_compile_mono_item<'tcx>( tcx: TyCtxt<'tcx>, mono_item: &MonoItem<'tcx>, ) -> DepNode { - DepNode::construct(tcx, DepKind::CompileMonoItem, mono_item) + DepNode::construct(tcx, dep_kinds::CompileMonoItem, mono_item) } -pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>; - -// We keep a lot of `DepNode`s in memory during compilation. It's not -// required that their size stay the same, but we don't want to change -// it inadvertently. This assert just ensures we're aware of any change. -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -static_assert_size!(DepNode, 18); - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -static_assert_size!(DepNode, 24); - pub trait DepNodeExt: Sized { /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 87436f9eeed..76ef62f9f27 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -6,49 +6,24 @@ use rustc_session::Session; #[macro_use] mod dep_node; +pub use rustc_query_system::dep_graph::debug::EdgeFilter; pub use rustc_query_system::dep_graph::{ - debug::DepNodeFilter, hash_result, DepContext, DepNodeColor, DepNodeIndex, - SerializedDepNodeIndex, WorkProduct, WorkProductId, WorkProductMap, + debug::DepNodeFilter, hash_result, DepContext, DepGraphQuery, DepNodeColor, DepNodeIndex, Deps, + SerializedDepGraph, SerializedDepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct, WorkProductId, + WorkProductMap, }; -pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt}; +pub use dep_node::{dep_kinds, label_strs, DepKind, DepNode, DepNodeExt}; pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; -pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>; +pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepsType>; -pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>; -pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>; -pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>; -pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>; -pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>; pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct<TyCtxt<'tcx>>; -impl rustc_query_system::dep_graph::DepKind for DepKind { - const NULL: Self = DepKind::Null; - const RED: Self = DepKind::Red; - const MAX: u16 = DepKind::VARIANTS - 1; - - fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}(", node.kind)?; - - ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - if let Some(def_id) = node.extract_def_id(tcx) { - write!(f, "{}", tcx.def_path_debug_str(def_id))?; - } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) { - write!(f, "{s}")?; - } else { - write!(f, "{}", node.hash)?; - } - } else { - write!(f, "{}", node.hash)?; - } - Ok(()) - })?; - - write!(f, ")") - } +#[derive(Clone)] +pub struct DepsType; +impl Deps for DepsType { fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R where OP: FnOnce() -> R, @@ -70,24 +45,13 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { }) } - #[track_caller] - #[inline] - fn from_u16(u: u16) -> Self { - if u > Self::MAX { - panic!("Invalid DepKind {u}"); - } - // SAFETY: See comment on DepKind::VARIANTS - unsafe { std::mem::transmute(u) } - } - - #[inline] - fn to_u16(self) -> u16 { - self as u16 - } + const DEP_KIND_NULL: DepKind = dep_kinds::Null; + const DEP_KIND_RED: DepKind = dep_kinds::Red; + const DEP_KIND_MAX: u16 = dep_node::DEP_KIND_VARIANTS - 1; } impl<'tcx> DepContext for TyCtxt<'tcx> { - type DepKind = DepKind; + type Deps = DepsType; #[inline] fn with_stable_hashing_context<R>(self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R { @@ -111,6 +75,6 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { #[inline] fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> { - &self.query_kinds[dk as usize] + &self.query_kinds[dk.as_usize()] } } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index f67f8015c04..3491c487f3e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -442,9 +442,10 @@ impl<'hir> Map<'hir> { /// Panics if `LocalDefId` does not have an associated body. pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind { match self.tcx.def_kind(def_id) { - DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => { - BodyOwnerKind::Const + DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => { + BodyOwnerKind::Const { inline: false } } + DefKind::InlineConst => BodyOwnerKind::Const { inline: true }, DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn, DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure, DefKind::Static(mt) => BodyOwnerKind::Static(mt), @@ -461,7 +462,7 @@ impl<'hir> Map<'hir> { /// just that it has to be checked as if it were. pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> { let ccx = match self.body_owner_kind(def_id) { - BodyOwnerKind::Const => ConstContext::Const, + BodyOwnerKind::Const { inline } => ConstContext::Const { inline }, BodyOwnerKind::Static(mt) => ConstContext::Static(mt), BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 037f84f476f..59849e8eb40 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -314,7 +314,10 @@ pub fn struct_lint_level( // Default allow lints trigger too often for testing. sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow, |incompat| { - matches!(incompat.reason, FutureIncompatibilityReason::FutureReleaseErrorReportNow) + matches!( + incompat.reason, + FutureIncompatibilityReason::FutureReleaseErrorReportInDeps + ) }, ); @@ -404,8 +407,8 @@ pub fn struct_lint_level( if let Some(future_incompatible) = future_incompatible { let explanation = match future_incompatible.reason { - FutureIncompatibilityReason::FutureReleaseError - | FutureIncompatibilityReason::FutureReleaseErrorReportNow => { + FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps + | FutureIncompatibilityReason::FutureReleaseErrorReportInDeps => { "this was previously accepted by the compiler but is being phased out; \ it will become a hard error in a future release!" .to_owned() diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 0115b1dcb3e..7c8a57b840b 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -6,13 +6,11 @@ use rustc_hir::{self as hir}; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, Size}; -use crate::mir::interpret::{ - alloc_range, AllocId, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar, -}; +use crate::mir::interpret::{alloc_range, AllocId, ConstAllocation, ErrorHandled, Scalar}; use crate::mir::{pretty_print_const_value, Promoted}; +use crate::ty::ScalarInt; use crate::ty::{self, print::pretty_print_const, List, Ty, TyCtxt}; use crate::ty::{GenericArgs, GenericArgsRef}; -use crate::ty::{ScalarInt, UserTypeAnnotationIndex}; /////////////////////////////////////////////////////////////////////////// /// Evaluated Constants @@ -178,29 +176,10 @@ impl<'tcx> ConstValue<'tcx> { /////////////////////////////////////////////////////////////////////////// /// Constants -/// -/// Two constants are equal if they are the same constant. Note that -/// this does not necessarily mean that they are `==` in Rust. In -/// particular, one must be wary of `NaN`! - -#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct Constant<'tcx> { - pub span: Span, - - /// Optional user-given type: for something like - /// `collect::<Vec<_>>`, this would be present and would - /// indicate that `Vec<_>` was explicitly specified. - /// - /// Needed for NLL to impose user-given type constraints. - pub user_ty: Option<UserTypeAnnotationIndex>, - - pub literal: ConstantKind<'tcx>, -} #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)] #[derive(TypeFoldable, TypeVisitable)] -pub enum ConstantKind<'tcx> { +pub enum Const<'tcx> { /// This constant came from the type system. /// /// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`; @@ -221,46 +200,27 @@ pub enum ConstantKind<'tcx> { Val(ConstValue<'tcx>, Ty<'tcx>), } -impl<'tcx> Constant<'tcx> { - pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> { - match self.literal.try_to_scalar() { - Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) { - GlobalAlloc::Static(def_id) => { - assert!(!tcx.is_thread_local_static(def_id)); - Some(def_id) - } - _ => None, - }, - _ => None, - } - } - #[inline] - pub fn ty(&self) -> Ty<'tcx> { - self.literal.ty() - } -} - -impl<'tcx> ConstantKind<'tcx> { +impl<'tcx> Const<'tcx> { #[inline(always)] pub fn ty(&self) -> Ty<'tcx> { match self { - ConstantKind::Ty(c) => c.ty(), - ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => *ty, + Const::Ty(c) => c.ty(), + Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty, } } #[inline] pub fn try_to_scalar(self) -> Option<Scalar> { match self { - ConstantKind::Ty(c) => match c.kind() { + Const::Ty(c) => match c.kind() { ty::ConstKind::Value(valtree) => match valtree { ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)), ty::ValTree::Branch(_) => None, }, _ => None, }, - ConstantKind::Val(val, _) => val.try_to_scalar(), - ConstantKind::Unevaluated(..) => None, + Const::Val(val, _) => val.try_to_scalar(), + Const::Unevaluated(..) => None, } } @@ -287,17 +247,17 @@ impl<'tcx> ConstantKind<'tcx> { span: Option<Span>, ) -> Result<ConstValue<'tcx>, ErrorHandled> { match self { - ConstantKind::Ty(c) => { + Const::Ty(c) => { // We want to consistently have a "clean" value for type system constants (i.e., no // data hidden in the padding), so we always go through a valtree here. let val = c.eval(tcx, param_env, span)?; Ok(tcx.valtree_to_const_val((self.ty(), val))) } - ConstantKind::Unevaluated(uneval, _) => { + Const::Unevaluated(uneval, _) => { // FIXME: We might want to have a `try_eval`-like function on `Unevaluated` tcx.const_eval_resolve(param_env, uneval, span) } - ConstantKind::Val(val, _) => Ok(val), + Const::Val(val, _) => Ok(val), } } @@ -332,23 +292,18 @@ impl<'tcx> ConstantKind<'tcx> { } #[inline] - pub fn try_eval_bits( - &self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> Option<u128> { + pub fn try_eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<u128> { let int = self.try_eval_scalar_int(tcx, param_env)?; - assert_eq!(self.ty(), ty); - let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; + let size = + tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size; int.to_bits(size).ok() } /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. #[inline] - pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 { - self.try_eval_bits(tcx, param_env, ty) - .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self)) + pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 { + self.try_eval_bits(tcx, param_env) + .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self)) } #[inline] @@ -416,7 +371,7 @@ impl<'tcx> ConstantKind<'tcx> { Self::Val(val, ty) } - /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly + /// Literals are converted to `Const::Val`, const generic parameters are eagerly /// converted to a constant, everything else becomes `Unevaluated`. #[instrument(skip(tcx), level = "debug", ret)] pub fn from_anon_const( @@ -552,29 +507,13 @@ impl<'tcx> UnevaluatedConst<'tcx> { } } -impl<'tcx> Debug for Constant<'tcx> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - write!(fmt, "{self}") - } -} - -impl<'tcx> Display for Constant<'tcx> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - match self.ty().kind() { - ty::FnDef(..) => {} - _ => write!(fmt, "const ")?, - } - Display::fmt(&self.literal, fmt) - } -} - -impl<'tcx> Display for ConstantKind<'tcx> { +impl<'tcx> Display for Const<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { match *self { - ConstantKind::Ty(c) => pretty_print_const(c, fmt, true), - ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt), + Const::Ty(c) => pretty_print_const(c, fmt, true), + Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt), // FIXME(valtrees): Correctly print mir constants. - ConstantKind::Unevaluated(..) => { + Const::Unevaluated(..) => { fmt.write_str("_")?; Ok(()) } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 1efb54bdb08..9ef67392291 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -45,16 +45,6 @@ impl ExpressionId { } } -rustc_index::newtype_index! { - /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their - /// array position in the LLVM coverage map "Expressions" array, which is assembled during the - /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s. - #[derive(HashStable)] - #[max = 0xFFFF_FFFF] - #[debug_format = "MappedExpressionIndex({})"] - pub struct MappedExpressionIndex {} -} - /// Operand of a coverage-counter expression. /// /// Operands can be a constant zero value, an actual coverage counter, or another diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 87180b56baa..0bb1c66da0c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -318,7 +318,7 @@ pub struct Body<'tcx> { /// Constants that are required to evaluate successfully for this MIR to be well-formed. /// We hold in this field all the constants we are not able to evaluate yet. - pub required_consts: Vec<Constant<'tcx>>, + pub required_consts: Vec<ConstOperand<'tcx>>, /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check. /// @@ -585,12 +585,12 @@ impl<'tcx> Body<'tcx> { &self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - normalize_const: impl Fn(ConstantKind<'tcx>) -> Result<ConstantKind<'tcx>, ErrorHandled>, + normalize_const: impl Fn(Const<'tcx>) -> Result<Const<'tcx>, ErrorHandled>, ) -> Result<(), ErrorHandled> { // For now, the only thing we have to check is is to ensure that all the constants used in // the body successfully evaluate. for &const_ in &self.required_consts { - let c = normalize_const(const_.literal)?; + let c = normalize_const(const_.const_)?; c.eval(tcx, param_env, Some(const_.span))?; } @@ -1096,7 +1096,7 @@ impl<'tcx> LocalDecl<'tcx> { pub enum VarDebugInfoContents<'tcx> { /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`. Place(Place<'tcx>), - Const(Constant<'tcx>), + Const(ConstOperand<'tcx>), } impl<'tcx> Debug for VarDebugInfoContents<'tcx> { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index da3ab1b2a57..b43176a02d8 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -696,6 +696,17 @@ impl Debug for Statement<'_> { } } +impl Display for NonDivergingIntrinsic<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Assume(op) => write!(f, "assume({op:?})"), + Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { + write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})") + } + } + } +} + impl<'tcx> Debug for TerminatorKind<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { self.fmt_head(fmt)?; @@ -1058,6 +1069,22 @@ impl<'tcx> Debug for Operand<'tcx> { } } +impl<'tcx> Debug for ConstOperand<'tcx> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + write!(fmt, "{self}") + } +} + +impl<'tcx> Display for ConstOperand<'tcx> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + match self.ty().kind() { + ty::FnDef(..) => {} + _ => write!(fmt, "const ")?, + } + Display::fmt(&self.const_, fmt) + } +} + impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { self.as_ref().fmt(fmt) @@ -1184,10 +1211,10 @@ fn use_verbose(ty: Ty<'_>, fn_def: bool) -> bool { } impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { - fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) { - let Constant { span, user_ty, literal } = constant; - if use_verbose(literal.ty(), true) { - self.push("mir::Constant"); + fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _location: Location) { + let ConstOperand { span, user_ty, const_ } = constant; + if use_verbose(const_.ty(), true) { + self.push("mir::ConstOperand"); self.push(&format!( "+ span: {}", self.tcx.sess.source_map().span_to_embeddable_string(*span) @@ -1209,8 +1236,8 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { ty::ValTree::Branch(_) => "Branch(..)".to_string(), }; - let val = match literal { - ConstantKind::Ty(ct) => match ct.kind() { + let val = match const_ { + Const::Ty(ct) => match ct.kind() { ty::ConstKind::Param(p) => format!("ty::Param({p})"), ty::ConstKind::Unevaluated(uv) => { format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,) @@ -1222,9 +1249,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { ty::ConstKind::Placeholder(_) | ty::ConstKind::Infer(_) | ty::ConstKind::Expr(_) - | ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", literal), + | ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", const_), }, - ConstantKind::Unevaluated(uv, _) => { + Const::Unevaluated(uv, _) => { format!( "Unevaluated({}, {:?}, {:?})", self.tcx.def_path_str(uv.def), @@ -1232,13 +1259,13 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { uv.promoted, ) } - ConstantKind::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)), + Const::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)), }; // This reflects what `Const` looked liked before `val` was renamed // as `kind`. We print it like this to avoid having to update // expected output in a lot of tests. - self.push(&format!("+ literal: Const {{ ty: {}, val: {} }}", literal.ty(), val)); + self.push(&format!("+ const_: Const {{ ty: {}, val: {} }}", const_.ty(), val)); } } @@ -1312,10 +1339,10 @@ pub fn write_allocations<'tcx>( struct CollectAllocIds(BTreeSet<AllocId>); impl<'tcx> Visitor<'tcx> for CollectAllocIds { - fn visit_constant(&mut self, c: &Constant<'tcx>, _: Location) { - match c.literal { - ConstantKind::Ty(_) | ConstantKind::Unevaluated(..) => {} - ConstantKind::Val(val, _) => { + fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) { + match c.const_ { + Const::Ty(_) | Const::Unevaluated(..) => {} + Const::Val(val, _) => { self.0.extend(alloc_ids_from_const_val(val)); } } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 25534f46960..5ac108bc829 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -1,5 +1,5 @@ /// Functionality for statements, operands, places, and things that appear in them. -use super::*; +use super::{interpret::GlobalAlloc, *}; /////////////////////////////////////////////////////////////////////////// // Statements @@ -302,10 +302,10 @@ impl<'tcx> Operand<'tcx> { span: Span, ) -> Self { let ty = Ty::new_fn_def(tcx, def_id, args); - Operand::Constant(Box::new(Constant { + Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - literal: ConstantKind::Val(ConstValue::ZeroSized, ty), + const_: Const::Val(ConstValue::ZeroSized, ty), })) } @@ -333,10 +333,10 @@ impl<'tcx> Operand<'tcx> { }; scalar_size == type_size }); - Operand::Constant(Box::new(Constant { + Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - literal: ConstantKind::Val(ConstValue::Scalar(val), ty), + const_: Const::Val(ConstValue::Scalar(val), ty), })) } @@ -356,9 +356,9 @@ impl<'tcx> Operand<'tcx> { } } - /// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a + /// Returns the `ConstOperand` that is the target of this `Operand`, or `None` if this `Operand` is a /// place. - pub fn constant(&self) -> Option<&Constant<'tcx>> { + pub fn constant(&self) -> Option<&ConstOperand<'tcx>> { match self { Operand::Constant(x) => Some(&**x), Operand::Copy(_) | Operand::Move(_) => None, @@ -370,11 +370,31 @@ impl<'tcx> Operand<'tcx> { /// While this is unlikely in general, it's the normal case of what you'll /// find as the `func` in a [`TerminatorKind::Call`]. pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> { - let const_ty = self.constant()?.literal.ty(); + let const_ty = self.constant()?.const_.ty(); if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None } } } +impl<'tcx> ConstOperand<'tcx> { + pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> { + match self.const_.try_to_scalar() { + Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) { + GlobalAlloc::Static(def_id) => { + assert!(!tcx.is_thread_local_static(def_id)); + Some(def_id) + } + _ => None, + }, + _ => None, + } + } + + #[inline] + pub fn ty(&self) -> Ty<'tcx> { + self.const_.ty() + } +} + /////////////////////////////////////////////////////////////////////////// /// Rvalues diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index f99084d0eb7..8f651b2a2db 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -3,7 +3,7 @@ //! This is in a dedicated file so that changes to this file can be reviewed more carefully. //! The intention is that this file only contains datatype declarations, no code. -use super::{BasicBlock, Constant, Local, UserTypeProjection}; +use super::{BasicBlock, Const, Local, UserTypeProjection}; use crate::mir::coverage::{CodeRegion, CoverageKind}; use crate::traits::Reveal; @@ -439,17 +439,6 @@ pub enum NonDivergingIntrinsic<'tcx> { CopyNonOverlapping(CopyNonOverlapping<'tcx>), } -impl std::fmt::Display for NonDivergingIntrinsic<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Assume(op) => write!(f, "assume({op:?})"), - Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { - write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})") - } - } - } -} - /// Describes what kind of retag is to be performed. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] @@ -913,10 +902,10 @@ pub enum InlineAsmOperand<'tcx> { out_place: Option<Place<'tcx>>, }, Const { - value: Box<Constant<'tcx>>, + value: Box<ConstOperand<'tcx>>, }, SymFn { - value: Box<Constant<'tcx>>, + value: Box<ConstOperand<'tcx>>, }, SymStatic { def_id: DefId, @@ -1136,7 +1125,22 @@ pub enum Operand<'tcx> { Move(Place<'tcx>), /// Constants are already semantically values, and remain unchanged. - Constant(Box<Constant<'tcx>>), + Constant(Box<ConstOperand<'tcx>>), +} + +#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub struct ConstOperand<'tcx> { + pub span: Span, + + /// Optional user-given type: for something like + /// `collect::<Vec<_>>`, this would be present and would + /// indicate that `Vec<_>` was explicitly specified. + /// + /// Needed for NLL to impose user-given type constraints. + pub user_ty: Option<UserTypeAnnotationIndex>, + + pub const_: Const<'tcx>, } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index f79697936d2..01c04f63890 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -227,7 +227,7 @@ impl<'tcx> Operand<'tcx> { { match self { &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, - Operand::Constant(c) => c.literal.ty(), + Operand::Constant(c) => c.const_.ty(), } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 61244b94289..51ec6da1ac8 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -186,7 +186,7 @@ macro_rules! make_mir_visitor { fn visit_constant( &mut self, - constant: & $($mutability)? Constant<'tcx>, + constant: & $($mutability)? ConstOperand<'tcx>, location: Location, ) { self.super_constant(constant, location); @@ -870,20 +870,20 @@ macro_rules! make_mir_visitor { fn super_constant( &mut self, - constant: & $($mutability)? Constant<'tcx>, + constant: & $($mutability)? ConstOperand<'tcx>, location: Location ) { - let Constant { + let ConstOperand { span, user_ty: _, // no visit method for this - literal, + const_, } = constant; self.visit_span($(& $mutability)? *span); - match literal { - ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location), - ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), - ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), + match const_ { + Const::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location), + Const::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), + Const::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 247fcd20c6c..8ba3764bcc3 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -116,9 +116,8 @@ impl EraseType for Result<ty::Const<'_>, mir::interpret::LitToConstError> { type Result = [u8; size_of::<Result<ty::Const<'static>, mir::interpret::LitToConstError>>()]; } -impl EraseType for Result<mir::ConstantKind<'_>, mir::interpret::LitToConstError> { - type Result = - [u8; size_of::<Result<mir::ConstantKind<'static>, mir::interpret::LitToConstError>>()]; +impl EraseType for Result<mir::Const<'_>, mir::interpret::LitToConstError> { + type Result = [u8; size_of::<Result<mir::Const<'static>, mir::interpret::LitToConstError>>()]; } impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> { @@ -266,6 +265,7 @@ trivial! { rustc_middle::ty::adjustment::CoerceUnsizedInfo, rustc_middle::ty::AssocItem, rustc_middle::ty::AssocItemContainer, + rustc_middle::ty::Asyncness, rustc_middle::ty::BoundVariableKind, rustc_middle::ty::DeducedParamAttrs, rustc_middle::ty::Destructor, @@ -311,7 +311,7 @@ macro_rules! tcx_lifetime { tcx_lifetime! { rustc_middle::hir::Owner, rustc_middle::middle::exported_symbols::ExportedSymbol, - rustc_middle::mir::ConstantKind, + rustc_middle::mir::Const, rustc_middle::mir::DestructuredConstant, rustc_middle::mir::ConstAlloc, rustc_middle::mir::ConstValue, diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index af4c57e702f..b1f83796862 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -416,7 +416,7 @@ impl<'tcx> Key for GenericArg<'tcx> { } } -impl<'tcx> Key for mir::ConstantKind<'tcx> { +impl<'tcx> Key for mir::Const<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; fn default_span(&self, _: TyCtxt<'_>) -> Span { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b5529568ff2..d888a2c0fb6 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -7,7 +7,6 @@ #![allow(unused_parens)] use crate::dep_graph; -use crate::dep_graph::DepKind; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintExpectation; use crate::metadata::ModChild; @@ -731,7 +730,7 @@ rustc_queries! { separate_provide_extern } - query asyncness(key: DefId) -> hir::IsAsync { + query asyncness(key: DefId) -> ty::Asyncness { desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } separate_provide_extern } @@ -1101,7 +1100,7 @@ rustc_queries! { desc { "destructuring type level constant"} } - /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index + /// Tries to destructure an `mir::Const` ADT or array into its variant index /// and its field values. This should only be used for pretty printing. query try_destructure_mir_constant_for_diagnostics( key: (mir::ConstValue<'tcx>, Ty<'tcx>) diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index a342b5231e9..34e5b02ba5b 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -37,7 +37,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> { pub eval_always: bool, pub dep_kind: DepKind, pub handle_cycle_error: HandleCycleError, - pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key, DepKind>>, + pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key>>, pub query_cache: FieldOffset<QueryCaches<'tcx>, C>, pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool, pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value, @@ -53,7 +53,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> { fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool, pub hash_result: HashResult<C::Value>, pub value_from_cycle_error: - fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>], guar: ErrorGuaranteed) -> C::Value, + fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> C::Value, pub format_value: fn(&C::Value) -> String, } @@ -402,7 +402,7 @@ macro_rules! define_callbacks { #[derive(Default)] pub struct QueryStates<'tcx> { $( - pub $name: QueryState<$($K)*, DepKind>, + pub $name: QueryState<$($K)*>, )* } @@ -516,7 +516,7 @@ macro_rules! define_feedable { } } None => { - let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key); + let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::dep_kinds::$name, &key); let dep_node_index = tcx.dep_graph.with_feed_task( dep_node, tcx, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index ebc1c11902b..8c39614903c 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -563,11 +563,11 @@ pub enum InlineAsmOperand<'tcx> { out_expr: Option<ExprId>, }, Const { - value: mir::ConstantKind<'tcx>, + value: mir::Const<'tcx>, span: Span, }, SymFn { - value: mir::ConstantKind<'tcx>, + value: mir::Const<'tcx>, span: Span, }, SymStatic { @@ -739,7 +739,7 @@ pub enum PatKind<'tcx> { /// * Opaque constants, that must not be matched structurally. So anything that does not derive /// `PartialEq` and `Eq`. Constant { - value: mir::ConstantKind<'tcx>, + value: mir::Const<'tcx>, }, Range(Box<PatRange<'tcx>>), @@ -769,8 +769,8 @@ pub enum PatKind<'tcx> { #[derive(Clone, Debug, PartialEq, HashStable)] pub struct PatRange<'tcx> { - pub lo: mir::ConstantKind<'tcx>, - pub hi: mir::ConstantKind<'tcx>, + pub lo: mir::Const<'tcx>, + pub hi: mir::Const<'tcx>, pub end: RangeEnd, } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 681400dbb94..b84e1568884 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -26,13 +26,13 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized { walk_pat(self, pat); } - // Note: We don't have visitors for `ty::Const` and `mir::ConstantKind` + // Note: We don't have visitors for `ty::Const` and `mir::Const` // (even though these types occur in THIR) for consistency and to reduce confusion, // since the lazy creation of constants during thir construction causes most - // 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that + // 'constants' to not be of type `ty::Const` or `mir::Const` at that // stage (they are mostly still identified by `DefId` or `hir::Lit`, see // the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`). - // You have to manually visit `ty::Const` and `mir::ConstantKind` through the + // You have to manually visit `ty::Const` and `mir::Const` through the // other `visit*` functions. } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 1340e674568..eef193a657d 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -378,6 +378,9 @@ pub enum ObligationCauseCode<'tcx> { /// `start` has wrong type StartFunctionType, + /// language function has wrong type + LangFunctionType(Symbol), + /// Intrinsic has wrong type IntrinsicType, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index ba871d6478b..2518f0cf2e9 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -339,24 +339,19 @@ impl<'tcx> Const<'tcx> { /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it /// contains const generic parameters or pointers). - pub fn try_eval_bits( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> Option<u128> { + pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> { let int = self.try_eval_scalar_int(tcx, param_env)?; - assert_eq!(self.ty(), ty); - let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; + let size = + tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size; // if `ty` does not depend on generic parameters, use an empty param_env int.to_bits(size).ok() } #[inline] /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. - pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 { - self.try_eval_bits(tcx, param_env, ty) - .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self)) + pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 { + self.try_eval_bits(tcx, param_env) + .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self)) } #[inline] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dbff13fdd8e..b050208b4a6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -280,6 +280,19 @@ impl fmt::Display for ImplPolarity { } } +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum Asyncness { + Yes, + No, +} + +impl Asyncness { + pub fn is_async(self) -> bool { + matches!(self, Asyncness::Yes) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)] pub enum Visibility<Id = LocalDefId> { /// Visible everywhere (including in other crates). diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index f1c38984296..f1093e88312 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -62,6 +62,7 @@ trivially_parameterized_over_tcx! { crate::middle::resolve_bound_vars::ObjectLifetimeDefault, crate::mir::ConstQualifs, ty::AssocItemContainer, + ty::Asyncness, ty::DeducedParamAttrs, ty::Generics, ty::ImplPolarity, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 268339ed402..b66c0f20990 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -479,7 +479,6 @@ TrivialTypeTraversalImpls! { ::rustc_target::asm::InlineAsmRegOrRegClass, crate::mir::coverage::CounterId, crate::mir::coverage::ExpressionId, - crate::mir::coverage::MappedExpressionIndex, crate::mir::Local, crate::mir::Promoted, crate::traits::Reveal, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3ebb8cbc476..f0526a23714 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2946,6 +2946,11 @@ impl<'tcx> Ty<'tcx> { } } + /// Returns `true` when the outermost type cannot be further normalized, + /// resolved, or substituted. This includes all primitive types, but also + /// things like ADTs and trait objects, sice even if their arguments or + /// nested types may be further simplified, the outermost [`TyKind`] or + /// type constructor remains the same. pub fn is_known_rigid(self) -> bool { match self.kind() { Bool diff --git a/compiler/rustc_middle/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs index 1b845334c49..9f1e4ac11c2 100644 --- a/compiler/rustc_middle/src/util/find_self_call.rs +++ b/compiler/rustc_middle/src/util/find_self_call.rs @@ -17,8 +17,8 @@ pub fn find_self_call<'tcx>( &body[block].terminator { debug!("find_self_call: func={:?}", func); - if let Operand::Constant(box Constant { literal, .. }) = func { - if let ty::FnDef(def_id, fn_args) = *literal.ty().kind() { + if let Operand::Constant(box ConstOperand { const_, .. }) = func { + if let ty::FnDef(def_id, fn_args) = *const_.ty().kind() { if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = tcx.opt_associated_item(def_id) { diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 962faf56cb8..dec06363380 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::DepKind; +use crate::dep_graph::dep_kinds; use crate::query::plumbing::CyclePlaceholder; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; @@ -13,34 +13,22 @@ use rustc_span::{ErrorGuaranteed, Span}; use std::fmt::Write; -impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - _: &[QueryInfo<DepKind>], - guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) } } } -impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> { - fn from_cycle_error( - _tcx: TyCtxt<'tcx>, - _: &[QueryInfo<DepKind>], - guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> { + fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self { Err(CyclePlaceholder(guar)) } } -impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - _: &[QueryInfo<DepKind>], - _guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { @@ -51,16 +39,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> { } } -impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - stack: &[QueryInfo<DepKind>], - guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> { + fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo], guar: ErrorGuaranteed) -> Self { let err = Ty::new_error(tcx, guar); let arity = if let Some(frame) = stack.get(0) - && frame.query.dep_kind == DepKind::fn_sig + && frame.query.dep_kind == dep_kinds::fn_sig && let Some(def_id) = frame.query.def_id && let Some(node) = tcx.hir().get_if_local(def_id) && let Some(sig) = node.fn_sig() @@ -85,16 +69,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> { } } -impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo<DepKind>], - _guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value<TyCtxt<'tcx>> for Representability { + fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { let mut item_and_field_ids = Vec::new(); let mut representable_ids = FxHashSet::default(); for info in cycle { - if info.query.dep_kind == DepKind::representability + if info.query.dep_kind == dep_kinds::representability && let Some(field_id) = info.query.def_id && let Some(field_id) = field_id.as_local() && let Some(DefKind::Field) = info.query.def_kind @@ -108,7 +88,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability { } } for info in cycle { - if info.query.dep_kind == DepKind::representability_adt_ty + if info.query.dep_kind == dep_kinds::representability_adt_ty && let Some(def_id) = info.query.ty_adt_id && let Some(def_id) = def_id.as_local() && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) @@ -121,32 +101,20 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability { } } -impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo<DepKind>], - guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<Ty<'_>> { + fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar)) } } -impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo<DepKind>], - guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> { + fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar)) } } -impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> { - fn from_cycle_error( - _tcx: TyCtxt<'tcx>, - _cycle: &[QueryInfo<DepKind>], - _guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>> { + fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really, // tcx.arena.alloc is pretty much equal to leaking). diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs index 4f1623b4c6a..fddcf9de7c7 100644 --- a/compiler/rustc_mir_build/src/build/cfg.rs +++ b/compiler/rustc_mir_build/src/build/cfg.rs @@ -49,7 +49,7 @@ impl<'tcx> CFG<'tcx> { block: BasicBlock, source_info: SourceInfo, temp: Place<'tcx>, - constant: Constant<'tcx>, + constant: ConstOperand<'tcx>, ) { self.push_assign( block, @@ -70,10 +70,10 @@ impl<'tcx> CFG<'tcx> { block, source_info, place, - Rvalue::Use(Operand::Constant(Box::new(Constant { + Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: source_info.span, user_ty: None, - literal: ConstantKind::zero_sized(tcx.types.unit), + const_: Const::zero_sized(tcx.types.unit), }))), ); } diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 0eff2df1366..fd2c57a0a6f 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -100,7 +100,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { expected: "constant pattern".to_string(), }); }; - values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty)); + values.push(value.eval_bits(self.tcx, self.param_env)); targets.push(self.parse_block(arm.body)?); } @@ -283,12 +283,12 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { ExprKind::StaticRef { alloc_id, ty, .. } => { let const_val = ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx)); - let literal = ConstantKind::Val(const_val, *ty); + let const_ = Const::Val(const_val, *ty); - Ok(Operand::Constant(Box::new(Constant { + Ok(Operand::Constant(Box::new(ConstOperand { span: expr.span, user_ty: None, - literal + const_ }))) }, ) @@ -301,7 +301,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { | ExprKind::NonHirLiteral { .. } | ExprKind::ConstBlock { .. } => Ok({ let value = as_constant_inner(expr, |_| None, self.tcx); - value.literal.eval_bits(self.tcx, self.param_env, value.ty()) + value.const_.eval_bits(self.tcx, self.param_env) }), ) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index d8232199e01..4ed49e78738 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -15,7 +15,7 @@ use rustc_target::abi::Size; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that /// `expr` is a valid compile-time constant! - pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> { + pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> ConstOperand<'tcx> { let this = self; let tcx = this.tcx; let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; @@ -42,62 +42,62 @@ pub fn as_constant_inner<'tcx>( expr: &Expr<'tcx>, push_cuta: impl FnMut(&Box<CanonicalUserType<'tcx>>) -> Option<UserTypeAnnotationIndex>, tcx: TyCtxt<'tcx>, -) -> Constant<'tcx> { +) -> ConstOperand<'tcx> { let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; match *kind { ExprKind::Literal { lit, neg } => { - let literal = - match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) { - Ok(c) => c, - Err(LitToConstError::Reported(guar)) => { - ConstantKind::Ty(ty::Const::new_error(tcx, guar, ty)) - } - Err(LitToConstError::TypeError) => { - bug!("encountered type error in `lit_to_mir_constant`") - } - }; - - Constant { span, user_ty: None, literal } + let const_ = match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) + { + Ok(c) => c, + Err(LitToConstError::Reported(guar)) => { + Const::Ty(ty::Const::new_error(tcx, guar, ty)) + } + Err(LitToConstError::TypeError) => { + bug!("encountered type error in `lit_to_mir_constant`") + } + }; + + ConstOperand { span, user_ty: None, const_ } } ExprKind::NonHirLiteral { lit, ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); - let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty); + let const_ = Const::Val(ConstValue::Scalar(Scalar::Int(lit)), ty); - Constant { span, user_ty, literal } + ConstOperand { span, user_ty, const_ } } ExprKind::ZstLiteral { ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); - let literal = ConstantKind::Val(ConstValue::ZeroSized, ty); + let const_ = Const::Val(ConstValue::ZeroSized, ty); - Constant { span, user_ty, literal } + ConstOperand { span, user_ty, const_ } } ExprKind::NamedConst { def_id, args, ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); let uneval = mir::UnevaluatedConst::new(def_id, args); - let literal = ConstantKind::Unevaluated(uneval, ty); + let const_ = Const::Unevaluated(uneval, ty); - Constant { user_ty, span, literal } + ConstOperand { user_ty, span, const_ } } ExprKind::ConstParam { param, def_id: _ } => { let const_param = ty::Const::new_param(tcx, param, expr.ty); - let literal = ConstantKind::Ty(const_param); + let const_ = Const::Ty(const_param); - Constant { user_ty: None, span, literal } + ConstOperand { user_ty: None, span, const_ } } ExprKind::ConstBlock { did: def_id, args } => { let uneval = mir::UnevaluatedConst::new(def_id, args); - let literal = ConstantKind::Unevaluated(uneval, ty); + let const_ = Const::Unevaluated(uneval, ty); - Constant { user_ty: None, span, literal } + ConstOperand { user_ty: None, span, const_ } } ExprKind::StaticRef { alloc_id, ty, .. } => { let const_val = ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &tcx)); - let literal = ConstantKind::Val(const_val, ty); + let const_ = Const::Val(const_val, ty); - Constant { span, user_ty: None, literal } + ConstOperand { span, user_ty: None, const_ } } _ => span_bug!(span, "expression is not a valid constant {:?}", kind), } @@ -107,7 +107,7 @@ pub fn as_constant_inner<'tcx>( fn lit_to_mir_constant<'tcx>( tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>, -) -> Result<ConstantKind<'tcx>, LitToConstError> { +) -> Result<Const<'tcx>, LitToConstError> { let LitToConstInput { lit, ty, neg } = lit_input; let trunc = |n| { let param_ty = ty::ParamEnv::reveal_all().and(ty); @@ -173,5 +173,5 @@ fn lit_to_mir_constant<'tcx>( _ => return Err(LitToConstError::TypeError), }; - Ok(ConstantKind::Val(value, ty)) + Ok(Const::Val(value, ty)) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 3220a184d49..d4089eef483 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -249,7 +249,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> { let range_val = - ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty)); + Const::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty)); let lit_op = this.literal_operand(expr.span, range_val); let is_bin_op = this.temp(bool_ty, expr_span); this.cfg.push_assign( @@ -485,10 +485,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { block = unpack!(this.stmt_expr(block, expr, None)); - block.and(Rvalue::Use(Operand::Constant(Box::new(Constant { + block.and(Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: expr_span, user_ty: None, - literal: ConstantKind::zero_sized(this.tcx.types.unit), + const_: Const::zero_sized(this.tcx.types.unit), })))) } @@ -817,7 +817,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { let param_ty = ty::ParamEnv::empty().and(ty); let size = self.tcx.layout_of(param_ty).unwrap().size; - let literal = ConstantKind::from_bits(self.tcx, size.unsigned_int_max(), param_ty); + let literal = Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty); self.literal_operand(span, literal) } @@ -828,7 +828,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let param_ty = ty::ParamEnv::empty().and(ty); let bits = self.tcx.layout_of(param_ty).unwrap().size.bits(); let n = 1 << (bits - 1); - let literal = ConstantKind::from_bits(self.tcx, n, param_ty); + let literal = Const::from_bits(self.tcx, n, param_ty); self.literal_operand(span, literal) } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 1e0a47ead8c..a4de42d45c9 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -114,10 +114,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { true_block, source_info, destination, - Constant { + ConstOperand { span: expr_span, user_ty: None, - literal: ConstantKind::from_bool(this.tcx, true), + const_: Const::from_bool(this.tcx, true), }, ); @@ -125,10 +125,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { false_block, source_info, destination, - Constant { + ConstOperand { span: expr_span, user_ty: None, - literal: ConstantKind::from_bool(this.tcx, false), + const_: Const::from_bool(this.tcx, false), }, ); @@ -186,10 +186,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { short_circuit, source_info, destination, - Constant { + ConstOperand { span: expr.span, user_ty: None, - literal: ConstantKind::from_bool(this.tcx, constant), + const_: Const::from_bool(this.tcx, constant), }, ); let rhs = unpack!(this.expr_into_dest(destination, continuation, &this.thir[rhs])); @@ -433,12 +433,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } thir::InlineAsmOperand::Const { value, span } => { mir::InlineAsmOperand::Const { - value: Box::new(Constant { span, user_ty: None, literal: value }), + value: Box::new(ConstOperand { + span, + user_ty: None, + const_: value, + }), } } thir::InlineAsmOperand::SymFn { value, span } => { mir::InlineAsmOperand::SymFn { - value: Box::new(Constant { span, user_ty: None, literal: value }), + value: Box::new(ConstOperand { + span, + user_ty: None, + const_: value, + }), } } thir::InlineAsmOperand::SymStatic { def_id } => { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 7e81c8b50c2..921a5ca1175 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1005,13 +1005,13 @@ enum TestKind<'tcx> { /// /// For `bool` we always generate two edges, one for `true` and one for /// `false`. - options: FxIndexMap<ConstantKind<'tcx>, u128>, + options: FxIndexMap<Const<'tcx>, u128>, }, /// Test for equality with value, possibly after an unsizing coercion to /// `ty`, Eq { - value: ConstantKind<'tcx>, + value: Const<'tcx>, // Integer types are handled by `SwitchInt`, and constants with ADT // types are converted back into patterns, so this can only be `&str`, // `&[T]`, `f32` or `f64`. @@ -1622,9 +1622,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // may want to add cases based on the candidates that are // available match test.kind { - TestKind::SwitchInt { switch_ty, ref mut options } => { + TestKind::SwitchInt { switch_ty: _, ref mut options } => { for candidate in candidates.iter() { - if !self.add_cases_to_switch(&match_place, candidate, switch_ty, options) { + if !self.add_cases_to_switch(&match_place, candidate, options) { break; } } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 484e8490919..795d1db8eec 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -85,8 +85,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, test_place: &PlaceBuilder<'tcx>, candidate: &Candidate<'pat, 'tcx>, - switch_ty: Ty<'tcx>, - options: &mut FxIndexMap<ConstantKind<'tcx>, u128>, + options: &mut FxIndexMap<Const<'tcx>, u128>, ) -> bool { let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) else { @@ -95,9 +94,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match match_pair.pattern.kind { PatKind::Constant { value } => { - options - .entry(value) - .or_insert_with(|| value.eval_bits(self.tcx, self.param_env, switch_ty)); + options.entry(value).or_insert_with(|| value.eval_bits(self.tcx, self.param_env)); true } PatKind::Variant { .. } => { @@ -255,10 +252,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, TerminatorKind::Call { - func: Operand::Constant(Box::new(Constant { + func: Operand::Constant(Box::new(ConstOperand { span: test.span, user_ty: None, - literal: method, + const_: method, })), args: vec![Operand::Move(ref_string)], destination: ref_str, @@ -388,7 +385,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>, source_info: SourceInfo, - value: ConstantKind<'tcx>, + value: Const<'tcx>, mut val: Place<'tcx>, mut ty: Ty<'tcx>, ) { @@ -485,7 +482,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, TerminatorKind::Call { - func: Operand::Constant(Box::new(Constant { + func: Operand::Constant(Box::new(ConstOperand { span: source_info.span, // FIXME(#54571): This constant comes from user input (a @@ -494,7 +491,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Need to experiment. user_ty: None, - literal: method, + const_: method, })), args: vec![Operand::Copy(val), expect], destination: eq_result, @@ -800,11 +797,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern) } - fn const_range_contains( - &self, - range: &PatRange<'tcx>, - value: ConstantKind<'tcx>, - ) -> Option<bool> { + fn const_range_contains(&self, range: &PatRange<'tcx>, value: Const<'tcx>) -> Option<bool> { use std::cmp::Ordering::*; // For performance, it's important to only do the second @@ -821,7 +814,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn values_not_contained_in_range( &self, range: &PatRange<'tcx>, - options: &FxIndexMap<ConstantKind<'tcx>, u128>, + options: &FxIndexMap<Const<'tcx>, u128>, ) -> Option<bool> { for &val in options.keys() { if self.const_range_contains(range, val)? { @@ -866,7 +859,7 @@ fn trait_method<'tcx>( trait_def_id: DefId, method_name: Symbol, args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, -) -> ConstantKind<'tcx> { +) -> Const<'tcx> { // The unhygienic comparison here is acceptable because this is only // used on known traits. let item = tcx @@ -877,5 +870,5 @@ fn trait_method<'tcx>( let method_ty = Ty::new_fn_def(tcx, item.def_id, args); - ConstantKind::zero_sized(method_ty) + Const::zero_sized(method_ty) } diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index 90d78658f96..c96e99ef0e7 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -25,19 +25,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Convenience function for creating a literal operand, one /// without any user type annotation. - pub(crate) fn literal_operand( - &mut self, - span: Span, - literal: ConstantKind<'tcx>, - ) -> Operand<'tcx> { - let constant = Box::new(Constant { span, user_ty: None, literal }); + pub(crate) fn literal_operand(&mut self, span: Span, const_: Const<'tcx>) -> Operand<'tcx> { + let constant = Box::new(ConstOperand { span, user_ty: None, const_ }); Operand::Constant(constant) } /// Returns a zero literal operand for the appropriate type, works for /// bool, char and integers. pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { - let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty)); + let literal = Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty)); self.literal_operand(span, literal) } @@ -54,10 +50,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, temp, - Constant { + ConstOperand { span: source_info.span, user_ty: None, - literal: ConstantKind::from_usize(self.tcx, value), + const_: Const::from_usize(self.tcx, value), }, ); temp diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 7748ffab79c..bba47056457 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -633,7 +633,7 @@ fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Bo _ => bug!("expected closure or generator, found {ty:?}"), } } - hir::BodyOwnerKind::Const => 0, + hir::BodyOwnerKind::Const { .. } => 0, hir::BodyOwnerKind::Static(_) => 0, }; let mut cfg = CFG { basic_blocks: IndexVec::new() }; @@ -700,7 +700,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Constants always need overflow checks. check_overflow |= matches!( tcx.hir().body_owner_kind(def), - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) + hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) ); let lint_level = LintLevel::Explicit(hir_id); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 18b0e9a643e..16a85d42761 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -647,21 +647,15 @@ impl<'tcx> Cx<'tcx> { out_expr: out_expr.map(|expr| self.mirror_expr(expr)), }, hir::InlineAsmOperand::Const { ref anon_const } => { - let value = mir::ConstantKind::from_anon_const( - tcx, - anon_const.def_id, - self.param_env, - ); + let value = + mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::Const { value, span } } hir::InlineAsmOperand::SymFn { ref anon_const } => { - let value = mir::ConstantKind::from_anon_const( - tcx, - anon_const.def_id, - self.param_env, - ); + let value = + mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::SymFn { value, span } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 1376344cfda..00d9fe72cfc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -27,7 +27,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self), ret)] pub(super) fn const_to_pat( &self, - cv: mir::ConstantKind<'tcx>, + cv: mir::Const<'tcx>, id: hir::HirId, span: Span, check_body_for_struct_match_violation: Option<DefId>, @@ -104,7 +104,7 @@ impl<'tcx> ConstToPat<'tcx> { fn to_pat( &mut self, - cv: mir::ConstantKind<'tcx>, + cv: mir::Const<'tcx>, check_body_for_struct_match_violation: Option<DefId>, ) -> Box<Pat<'tcx>> { trace!(self.treat_byte_string_as_slice); @@ -124,7 +124,7 @@ impl<'tcx> ConstToPat<'tcx> { debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation); let inlined_const_as_pat = match cv { - mir::ConstantKind::Ty(c) => match c.kind() { + mir::Const::Ty(c) => match c.kind() { ty::ConstKind::Param(_) | ty::ConstKind::Infer(_) | ty::ConstKind::Bound(_, _) @@ -144,10 +144,10 @@ impl<'tcx> ConstToPat<'tcx> { }) }), }, - mir::ConstantKind::Unevaluated(_, _) => { + mir::Const::Unevaluated(_, _) => { span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}") } - mir::ConstantKind::Val(_, _) => Box::new(Pat { + mir::Const::Val(_, _) => Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Constant { value: cv }, @@ -385,9 +385,9 @@ impl<'tcx> ConstToPat<'tcx> { ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // `&str` is represented as a valtree, let's keep using this // optimization for now. - ty::Str => PatKind::Constant { - value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)), - }, + ty::Str => { + PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } + } // Backwards compatibility hack: support references to non-structural types, // but hard error if we aren't behind a double reference. We could just use // the fallback code path below, but that would allow *more* of this fishy @@ -445,9 +445,9 @@ impl<'tcx> ConstToPat<'tcx> { } } }, - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => PatKind::Constant { - value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)), - }, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => { + PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } + } ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(), _ => { self.saw_const_match_error.set(true); diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index bee1c4e4614..b79beb1c537 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -137,16 +137,16 @@ impl IntRange { fn from_constant<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: mir::ConstantKind<'tcx>, + value: mir::Const<'tcx>, ) -> Option<IntRange> { let ty = value.ty(); let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, ty)?; let val = match value { - mir::ConstantKind::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => { + mir::Const::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => { valtree.unwrap_leaf().to_bits(target_size).ok() }, // This is a more general form of the previous case. - _ => value.try_eval_bits(tcx, param_env, ty), + _ => value.try_eval_bits(tcx, param_env), }?; let val = val ^ bias; @@ -225,8 +225,8 @@ impl IntRange { let (lo, hi) = (lo ^ bias, hi ^ bias); let env = ty::ParamEnv::empty().and(ty); - let lo_const = mir::ConstantKind::from_bits(tcx, lo, env); - let hi_const = mir::ConstantKind::from_bits(tcx, hi, env); + let lo_const = mir::Const::from_bits(tcx, lo, env); + let hi_const = mir::Const::from_bits(tcx, hi, env); let kind = if lo == hi { PatKind::Constant { value: lo_const } @@ -619,9 +619,9 @@ pub(super) enum Constructor<'tcx> { /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). IntRange(IntRange), /// Ranges of floating-point literal values (`2.0..=5.2`). - FloatRange(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>, RangeEnd), + FloatRange(mir::Const<'tcx>, mir::Const<'tcx>, RangeEnd), /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. - Str(mir::ConstantKind<'tcx>), + Str(mir::Const<'tcx>), /// Array and slice patterns. Slice(Slice), /// Constants that must not be matched structurally. They are treated as black @@ -1379,8 +1379,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let ty = lo.ty(); ctor = if let Some(int_range) = IntRange::from_range( cx.tcx, - lo.eval_bits(cx.tcx, cx.param_env, lo.ty()), - hi.eval_bits(cx.tcx, cx.param_env, hi.ty()), + lo.eval_bits(cx.tcx, cx.param_env), + hi.eval_bits(cx.tcx, cx.param_env), ty, &end, ) { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3d9e634c849..f1f75c26717 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -20,7 +20,7 @@ use rustc_index::Idx; use rustc_middle::mir::interpret::{ ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar, }; -use rustc_middle::mir::{self, ConstantKind, UserTypeProjection}; +use rustc_middle::mir::{self, Const, UserTypeProjection}; use rustc_middle::mir::{BorrowKind, Mutability}; use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange}; use rustc_middle::ty::CanonicalUserTypeAnnotation; @@ -100,8 +100,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_range( &mut self, ty: Ty<'tcx>, - lo: mir::ConstantKind<'tcx>, - hi: mir::ConstantKind<'tcx>, + lo: mir::Const<'tcx>, + hi: mir::Const<'tcx>, end: RangeEnd, span: Span, lo_expr: Option<&hir::Expr<'tcx>>, @@ -131,7 +131,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr && let rustc_ast::ast::LitKind::Int(val, _) = lit.node { - if lo.eval_bits(self.tcx, self.param_env, ty) != val { + if lo.eval_bits(self.tcx, self.param_env) != val { lower_overflow = true; self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); } @@ -139,7 +139,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr && let rustc_ast::ast::LitKind::Int(val, _) = lit.node { - if hi.eval_bits(self.tcx, self.param_env, ty) != val { + if hi.eval_bits(self.tcx, self.param_env) != val { higher_overflow = true; self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); } @@ -162,7 +162,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr && let rustc_ast::ast::LitKind::Int(val, _) = lit.node { - if lo.eval_bits(self.tcx, self.param_env, ty) != val { + if lo.eval_bits(self.tcx, self.param_env) != val { lower_overflow = true; self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); } @@ -170,7 +170,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr && let rustc_ast::ast::LitKind::Int(val, _) = lit.node { - if hi.eval_bits(self.tcx, self.param_env, ty) != val { + if hi.eval_bits(self.tcx, self.param_env) != val { higher_overflow = true; self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); } @@ -191,18 +191,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty: Ty<'tcx>, lo: Option<&PatKind<'tcx>>, hi: Option<&PatKind<'tcx>>, - ) -> Option<(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>)> { + ) -> Option<(mir::Const<'tcx>, mir::Const<'tcx>)> { match (lo, hi) { (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => { Some((*lo, *hi)) } (Some(PatKind::Constant { value: lo }), None) => { let hi = ty.numeric_max_val(self.tcx)?; - Some((*lo, mir::ConstantKind::from_ty_const(hi, self.tcx))) + Some((*lo, mir::Const::from_ty_const(hi, self.tcx))) } (None, Some(PatKind::Constant { value: hi })) => { let lo = ty.numeric_min_val(self.tcx)?; - Some((mir::ConstantKind::from_ty_const(lo, self.tcx), *hi)) + Some((mir::Const::from_ty_const(lo, self.tcx), *hi)) } _ => None, } @@ -525,8 +525,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .tcx .const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span)) .map(|val| match val { - Some(valtree) => mir::ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)), - None => mir::ConstantKind::Val( + Some(valtree) => mir::Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), + None => mir::Const::Val( self.tcx .const_eval_global_id(param_env_reveal_all, cid, Some(span)) .expect("const_eval_global_id_for_typeck should have already failed"), @@ -608,7 +608,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; if let Some(lit_input) = lit_input { match tcx.at(expr.span).lit_to_const(lit_input) { - Ok(c) => return self.const_to_pat(ConstantKind::Ty(c), id, span, None).kind, + Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind, // If an error occurred, ignore that it's a literal // and leave reporting the error up to const eval of // the unevaluated constant below. @@ -632,7 +632,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span)) { self.const_to_pat( - ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)), + Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), id, span, None, @@ -641,7 +641,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } else { // If that fails, convert it to an opaque constant pattern. match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) { - Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind, + Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind, Err(ErrorHandled::TooGeneric(_)) => { // If we land here it means the const can't be evaluated because it's `TooGeneric`. self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); @@ -678,7 +678,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; match self.tcx.at(expr.span).lit_to_const(lit_input) { Ok(constant) => { - self.const_to_pat(ConstantKind::Ty(constant), expr.hir_id, lit.span, None).kind + self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind } Err(LitToConstError::Reported(_)) => PatKind::Wild, Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), @@ -838,8 +838,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { #[instrument(skip(tcx), level = "debug")] pub(crate) fn compare_const_vals<'tcx>( tcx: TyCtxt<'tcx>, - a: mir::ConstantKind<'tcx>, - b: mir::ConstantKind<'tcx>, + a: mir::Const<'tcx>, + b: mir::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<Ordering> { assert_eq!(a.ty(), b.ty()); @@ -855,18 +855,18 @@ pub(crate) fn compare_const_vals<'tcx>( ty::Float(_) | ty::Int(_) => {} // require special handling, see below _ => match (a, b) { ( - mir::ConstantKind::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty), - mir::ConstantKind::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty), + mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty), + mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty), ) => return Some(a.cmp(&b)), - (mir::ConstantKind::Ty(a), mir::ConstantKind::Ty(b)) => { + (mir::Const::Ty(a), mir::Const::Ty(b)) => { return Some(a.kind().cmp(&b.kind())); } _ => {} }, } - let a = a.eval_bits(tcx, param_env, ty); - let b = b.eval_bits(tcx, param_env, ty); + let a = a.eval_bits(tcx, param_env); + let b = b.eval_bits(tcx, param_env); use rustc_apfloat::Float; match *ty.kind() { diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index ad5f83d9e25..e24685cb90f 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -973,10 +973,10 @@ where } fn constant_usize(&self, val: u16) -> Operand<'tcx> { - Operand::Constant(Box::new(Constant { + Operand::Constant(Box::new(ConstOperand { span: self.source_info.span, user_ty: None, - literal: ConstantKind::from_usize(self.tcx(), val.into()), + const_: Const::from_usize(self.tcx(), val.into()), })) } diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 775c522b476..1ebb59b3a63 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -190,7 +190,7 @@ impl PeekCall { if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = &terminator.kind { - if let ty::FnDef(def_id, fn_args) = *func.literal.ty().kind() { + if let ty::FnDef(def_id, fn_args) = *func.const_.ty().kind() { let name = tcx.item_name(def_id); if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek { return None; diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 514146b5030..dd20e5d7430 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -225,7 +225,7 @@ pub trait ValueAnalysis<'tcx> { fn handle_constant( &self, - constant: &Constant<'tcx>, + constant: &ConstOperand<'tcx>, state: &mut State<Self::Value>, ) -> Self::Value { self.super_constant(constant, state) @@ -233,7 +233,7 @@ pub trait ValueAnalysis<'tcx> { fn super_constant( &self, - _constant: &Constant<'tcx>, + _constant: &ConstOperand<'tcx>, _state: &mut State<Self::Value>, ) -> Self::Value { Self::Value::TOP diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index fe66a9a0994..28765af20ad 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -181,13 +181,10 @@ fn insert_alignment_check<'tcx>( // Subtract 1 from the alignment to get the alignment mask let alignment_mask = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - let one = Operand::Constant(Box::new(Constant { + let one = Operand::Constant(Box::new(ConstOperand { span: source_info.span, user_ty: None, - literal: ConstantKind::Val( - ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), - tcx.types.usize, - ), + const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize), })); block_data.statements.push(Statement { source_info, @@ -213,13 +210,10 @@ fn insert_alignment_check<'tcx>( // Check if the alignment bits are all zero let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - let zero = Operand::Constant(Box::new(Constant { + let zero = Operand::Constant(Box::new(ConstOperand { span: source_info.span, user_ty: None, - literal: ConstantKind::Val( - ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), - tcx.types.usize, - ), + const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize), })); block_data.statements.push(Statement { source_info, diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index d5af321d726..bacabc62ee4 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -142,9 +142,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) { if let Operand::Constant(constant) = op { - let maybe_uneval = match constant.literal { - ConstantKind::Val(..) | ConstantKind::Ty(_) => None, - ConstantKind::Unevaluated(uv, _) => Some(uv), + let maybe_uneval = match constant.const_ { + Const::Val(..) | Const::Ty(_) => None, + Const::Unevaluated(uv, _) => Some(uv), }; if let Some(uv) = maybe_uneval { diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs index f662ce645b0..40cd2825408 100644 --- a/compiler/rustc_mir_transform/src/const_debuginfo.rs +++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs @@ -4,7 +4,7 @@ use rustc_middle::{ mir::{ visit::{PlaceContext, Visitor}, - Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents, + Body, ConstOperand, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents, }, ty::TyCtxt, }; @@ -45,7 +45,7 @@ struct LocalUseVisitor { local_assignment_locations: IndexVec<Local, Option<Location>>, } -fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> { +fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, ConstOperand<'tcx>)> { let mut visitor = LocalUseVisitor { local_mutating_uses: IndexVec::from_elem(0, &body.local_decls), local_assignment_locations: IndexVec::from_elem(None, &body.local_decls), diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index e175f22d7a9..fd2d37dbea5 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -96,10 +96,10 @@ impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> { let (discr, targets) = target_bb_terminator.kind.as_switch()?; if discr.place() == Some(*place) { let switch_ty = place.ty(self.body.local_decls(), self.tcx).ty; + debug_assert_eq!(switch_ty, _const.ty()); // We now know that the Switch matches on the const place, and it is statementless // Now find which value in the Switch matches the const value. - let const_value = - _const.literal.try_eval_bits(self.tcx, self.param_env, switch_ty)?; + let const_value = _const.const_.try_eval_bits(self.tcx, self.param_env)?; let target_to_use_in_goto = targets.target_for_value(const_value); self.optimizations.push(OptimizationToApply { bb_with_goto: location.block, diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index c6aac2ca213..4fc78b28580 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -210,7 +210,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _bin_op: BinOp, _left: &ImmTy<'tcx>, _right: &ImmTy<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> { // We can't do this because aliasing of memory can differ between const eval and llvm throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } @@ -525,7 +525,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<ConstantKind<'tcx>> { + fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<Const<'tcx>> { // This will return None if the above `const_prop` invocation only "wrote" a // type whose creation requires no write. E.g. a generator whose initial state // consists solely of uninitialized memory (so it doesn't capture any locals). @@ -541,7 +541,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let Right(imm) = imm else { return None }; match *imm { Immediate::Scalar(scalar) if scalar.try_to_int().is_ok() => { - Some(ConstantKind::from_scalar(self.tcx, scalar, value.layout.ty)) + Some(Const::from_scalar(self.tcx, scalar, value.layout.ty)) } Immediate::ScalarPair(l, r) if l.try_to_int().is_ok() && r.try_to_int().is_ok() => { let alloc_id = self @@ -551,7 +551,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { }) .ok()?; - Some(ConstantKind::Val( + Some(Const::Val( ConstValue::Indirect { alloc_id, offset: Size::ZERO }, value.layout.ty, )) @@ -731,7 +731,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { if let Some(()) = self.eval_rvalue_with_identities(rvalue, *place) { // If this was already an evaluated constant, keep it. if let Rvalue::Use(Operand::Constant(c)) = rvalue - && let ConstantKind::Val(..) = c.literal + && let Const::Val(..) = c.const_ { trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); } else if let Some(operand) = self.replace_with_const(*place) { diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index fb33b3b49d3..64e262c6c93 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -281,7 +281,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } /// Returns the value, if any, of evaluating `c`. - fn eval_constant(&mut self, c: &Constant<'tcx>, location: Location) -> Option<OpTy<'tcx>> { + fn eval_constant(&mut self, c: &ConstOperand<'tcx>, location: Location) -> Option<OpTy<'tcx>> { // FIXME we need to revisit this for #67176 if c.has_param() { return None; @@ -293,7 +293,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // that the `RevealAll` pass has happened and that the body's consts // are normalized, so any call to resolve before that needs to be // manually normalized. - let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.literal).ok()?; + let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?; self.use_ecx(location, |this| this.ecx.eval_mir_constant(&val, Some(c.span), None)) } @@ -322,7 +322,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn check_unary_op(&mut self, op: UnOp, arg: &Operand<'tcx>, location: Location) -> Option<()> { if let (val, true) = self.use_ecx(location, |this| { let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?; - let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?; + let (_res, overflow) = this.ecx.overflowing_unary_op(op, &val)?; Ok((val, overflow)) })? { // `AssertKind` only has an `OverflowNeg` variant, so make sure that is @@ -390,7 +390,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if let (Some(l), Some(r)) = (l, r) { // The remaining operators are handled through `overflowing_binary_op`. if self.use_ecx(location, |this| { - let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?; + let (_res, overflow) = this.ecx.overflowing_binary_op(op, &l, &r)?; Ok(overflow) })? { let source_info = self.body().source_info(location); @@ -580,7 +580,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { self.super_operand(operand, location); } - fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { trace!("visit_constant: {:?}", constant); self.super_constant(constant, location); self.eval_constant(constant, location); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index cf827c98894..7b14fef6153 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -206,7 +206,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { && let operand_ty = operand.ty(self.local_decls, self.tcx) && let Some(operand_ty) = operand_ty.builtin_deref(true) && let ty::Array(_, len) = operand_ty.ty.kind() - && let Some(len) = ConstantKind::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env) + && let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env) { state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map()); } @@ -224,7 +224,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { Rvalue::Len(place) => { let place_ty = place.ty(self.local_decls, self.tcx); if let ty::Array(_, len) = place_ty.ty.kind() { - ConstantKind::Ty(*len) + Const::Ty(*len) .try_eval_scalar(self.tcx, self.param_env) .map_or(FlatSet::Top, FlatSet::Elem) } else if let [ProjectionElem::Deref] = place.projection[..] { @@ -234,21 +234,27 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => { + let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else { + return ValueOrPlace::Value(FlatSet::Top); + }; match self.eval_operand(operand, state) { FlatSet::Elem(op) => self .ecx - .int_to_int_or_float(&op, *ty) - .map_or(FlatSet::Top, |result| self.wrap_immediate(result)), + .int_to_int_or_float(&op, layout) + .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, } } Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => { + let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else { + return ValueOrPlace::Value(FlatSet::Top); + }; match self.eval_operand(operand, state) { FlatSet::Elem(op) => self .ecx - .float_to_float_or_int(&op, *ty) - .map_or(FlatSet::Top, |result| self.wrap_immediate(result)), + .float_to_float_or_int(&op, layout) + .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, } @@ -268,7 +274,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) { FlatSet::Elem(value) => self .ecx - .unary_op(*op, &value) + .wrapping_unary_op(*op, &value) .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, @@ -295,11 +301,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { fn handle_constant( &self, - constant: &Constant<'tcx>, + constant: &ConstOperand<'tcx>, _state: &mut State<Self::Value>, ) -> Self::Value { constant - .literal + .const_ .try_eval_scalar(self.tcx, self.param_env) .map_or(FlatSet::Top, FlatSet::Elem) } @@ -360,7 +366,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Operand::Constant(box constant) => { - if let Ok(constant) = self.ecx.eval_mir_constant(&constant.literal, None, None) { + if let Ok(constant) = self.ecx.eval_mir_constant(&constant.const_, None, None) { self.assign_constant(state, place, constant, &[]); } } @@ -439,7 +445,9 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // Both sides are known, do the actual computation. (FlatSet::Elem(left), FlatSet::Elem(right)) => { match self.ecx.overflowing_binary_op(op, &left, &right) { - Ok((val, overflow, _)) => (FlatSet::Elem(val), FlatSet::Elem(overflow)), + Ok((val, overflow)) => { + (FlatSet::Elem(val.to_scalar()), FlatSet::Elem(overflow)) + } _ => (FlatSet::Top, FlatSet::Top), } } @@ -518,10 +526,10 @@ pub(crate) struct Patch<'tcx> { /// For a given MIR location, this stores the values of the operands used by that location. In /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are /// properly captured. (This may become UB soon, but it is currently emitted even by safe code.) - pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), ConstantKind<'tcx>>, + pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), Const<'tcx>>, /// Stores the assigned values for assignments where the Rvalue is constant. - pub(crate) assignments: FxHashMap<Location, ConstantKind<'tcx>>, + pub(crate) assignments: FxHashMap<Location, Const<'tcx>>, } impl<'tcx> Patch<'tcx> { @@ -529,8 +537,8 @@ impl<'tcx> Patch<'tcx> { Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() } } - fn make_operand(&self, literal: ConstantKind<'tcx>) -> Operand<'tcx> { - Operand::Constant(Box::new(Constant { span: DUMMY_SP, user_ty: None, literal })) + fn make_operand(&self, const_: Const<'tcx>) -> Operand<'tcx> { + Operand::Constant(Box::new(ConstOperand { span: DUMMY_SP, user_ty: None, const_ })) } } @@ -549,12 +557,12 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> { place: Place<'tcx>, state: &State<FlatSet<Scalar>>, map: &Map, - ) -> Option<ConstantKind<'tcx>> { + ) -> Option<Const<'tcx>> { let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else { return None; }; let ty = place.ty(self.local_decls, self.patch.tcx).ty; - Some(ConstantKind::Val(ConstValue::Scalar(value.into()), ty)) + Some(Const::Val(ConstValue::Scalar(value.into()), ty)) } } @@ -783,8 +791,8 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm _bin_op: BinOp, _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, - ) -> interpret::InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)> { - throw_unsup!(Unsupported("".into())) + ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> { + crate::const_prop::throw_machine_stop_str!("can't do pointer arithmetic"); } fn expose_ptr( diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs index 909116a77f5..666293cbc30 100644 --- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs +++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs @@ -150,7 +150,7 @@ fn rvalue_hash<H: Hasher>(hasher: &mut H, rvalue: &Rvalue<'_>) { fn operand_hash<H: Hasher>(hasher: &mut H, operand: &Operand<'_>) { match operand { - Operand::Constant(box Constant { user_ty: _, literal, span: _ }) => literal.hash(hasher), + Operand::Constant(box ConstOperand { user_ty: _, const_, span: _ }) => const_.hash(hasher), x => x.hash(hasher), }; } @@ -179,9 +179,9 @@ fn rvalue_eq<'tcx>(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool { fn operand_eq<'tcx>(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool { let res = match (lhs, rhs) { ( - Operand::Constant(box Constant { user_ty: _, literal, span: _ }), - Operand::Constant(box Constant { user_ty: _, literal: literal2, span: _ }), - ) => literal == literal2, + Operand::Constant(box ConstOperand { user_ty: _, const_, span: _ }), + Operand::Constant(box ConstOperand { user_ty: _, const_: const2, span: _ }), + ) => const_ == const2, (x, y) => x == y, }; debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 78d7ffb3698..6a89d067275 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -402,10 +402,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> { - Rvalue::Use(Operand::Constant(Box::new(Constant { + Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - literal: ConstantKind::from_bool(self.tcx, val), + const_: Const::from_bool(self.tcx, val), }))) } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index eae83448c46..96c60fdf41b 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1189,10 +1189,10 @@ fn insert_panic_block<'tcx>( ) -> BasicBlock { let assert_block = BasicBlock::new(body.basic_blocks.len()); let term = TerminatorKind::Assert { - cond: Operand::Constant(Box::new(Constant { + cond: Operand::Constant(Box::new(ConstOperand { span: body.span, user_ty: None, - literal: ConstantKind::from_bool(tcx, false), + const_: Const::from_bool(tcx, false), })), expected: true, msg: Box::new(message), diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 4dc7c3b6444..1d9c89477cb 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -652,11 +652,11 @@ impl<'tcx> Inliner<'tcx> { // `required_consts`, here we may not only have `ConstKind::Unevaluated` // because we are calling `subst_and_normalize_erasing_regions`. caller_body.required_consts.extend( - callee_body.required_consts.iter().copied().filter(|&ct| match ct.literal { - ConstantKind::Ty(_) => { + callee_body.required_consts.iter().copied().filter(|&ct| match ct.const_ { + Const::Ty(_) => { bug!("should never encounter ty::UnevaluatedConst in `required_consts`") } - ConstantKind::Val(..) | ConstantKind::Unevaluated(..) => true, + Const::Val(..) | Const::Unevaluated(..) => true, }), ); } @@ -824,7 +824,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { } } TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => { - let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.literal.ty())); + let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.const_.ty())); self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) { // Don't give intrinsics the extra penalty for calls INSTR_COST diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 6e191b285be..a6ef2e11aa8 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -104,7 +104,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { fn try_eval_bool(&self, a: &Operand<'_>) -> Option<bool> { let a = a.constant()?; - if a.literal.ty().is_bool() { a.literal.try_to_bool() } else { None } + if a.const_.ty().is_bool() { a.const_.try_to_bool() } else { None } } /// Transform "&(*a)" ==> "a". @@ -136,8 +136,8 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { return; } - let literal = ConstantKind::from_ty_const(len, self.tcx); - let constant = Constant { span: source_info.span, literal, user_ty: None }; + let const_ = Const::from_ty_const(len, self.tcx); + let constant = ConstOperand { span: source_info.span, const_, user_ty: None }; *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); } } diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index fc49c9ba348..4eee45f8d00 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -149,10 +149,10 @@ impl EnumSizeOpt { }; let place = Place::from(size_array_local); - let constant_vals = Constant { + let constant_vals = ConstOperand { span, user_ty: None, - literal: ConstantKind::Val( + const_: Const::Val( ConstValue::Indirect { alloc_id, offset: Size::ZERO }, tmp_ty, ), diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 70d4ea74d1a..d55b0cbe635 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -31,9 +31,9 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_index::IndexVec; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{ - traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, - MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, - Statement, StatementKind, TerminatorKind, START_BLOCK, + traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, + LocalDecl, MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, + SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK, }; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; @@ -149,14 +149,14 @@ fn remap_mir_for_const_eval_select<'tcx>( let terminator = bb.terminator.as_mut().expect("invalid terminator"); match terminator.kind { TerminatorKind::Call { - func: Operand::Constant(box Constant { ref literal, .. }), + func: Operand::Constant(box ConstOperand { ref const_, .. }), ref mut args, destination, target, unwind, fn_span, .. - } if let ty::FnDef(def_id, _) = *literal.ty().kind() + } if let ty::FnDef(def_id, _) = *const_.ty().kind() && tcx.item_name(def_id) == sym::const_eval_select && tcx.is_intrinsic(def_id) => { @@ -343,7 +343,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { let body = match tcx.hir().body_const_context(def) { // consts and statics do not have `optimized_mir`, so we can steal the body instead of // cloning it. - Some(hir::ConstContext::Const | hir::ConstContext::Static(_)) => body.steal(), + Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => body.steal(), Some(hir::ConstContext::ConstFn) => body.borrow().clone(), None => bug!("`mir_for_ctfe` called on non-const {def:?}"), }; diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 13277d62bf4..0d2d764c422 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -32,10 +32,10 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { source_info: terminator.source_info, kind: StatementKind::Assign(Box::new(( *destination, - Rvalue::Use(Operand::Constant(Box::new(Constant { + Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: terminator.source_info.span, user_ty: None, - literal: ConstantKind::zero_sized(tcx.types.unit), + const_: Const::zero_sized(tcx.types.unit), }))), ))), }); diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index bc29fb8ded1..3dc627b6146 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -98,10 +98,10 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), ) if lhs_f == lhs_s - && f_c.literal.ty().is_bool() - && s_c.literal.ty().is_bool() - && f_c.literal.try_eval_bool(tcx, param_env).is_some() - && s_c.literal.try_eval_bool(tcx, param_env).is_some() => {} + && f_c.const_.ty().is_bool() + && s_c.const_.ty().is_bool() + && f_c.const_.try_eval_bool(tcx, param_env).is_some() + && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {} // Otherwise we cannot optimize. Try another block. _ => continue 'outer, @@ -128,8 +128,8 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))), ) => { // From earlier loop we know that we are dealing with bool constants only: - let f_b = f_c.literal.try_eval_bool(tcx, param_env).unwrap(); - let s_b = s_c.literal.try_eval_bool(tcx, param_env).unwrap(); + let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap(); + let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap(); if f_b == s_b { // Same value in both blocks. Use statement as is. (*f).clone() diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 1b846987d38..d1a4b26a046 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -90,10 +90,10 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { && let [PlaceElem::Deref] = &place.projection[..] && let Some(len) = self.slice_lengths[place.local] { - *rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant { + *rvalue = Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: rustc_span::DUMMY_SP, user_ty: None, - literal: ConstantKind::from_ty_const(len, self.tcx), + const_: Const::from_ty_const(len, self.tcx), }))); } self.super_rvalue(rvalue, loc); diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index dcc4cd85cda..a34d4b02764 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -62,12 +62,12 @@ impl<'tcx> Replacer<'_, 'tcx> { layout.is_zst() } - fn make_zst(&self, ty: Ty<'tcx>) -> Constant<'tcx> { + fn make_zst(&self, ty: Ty<'tcx>) -> ConstOperand<'tcx> { debug_assert!(self.known_to_be_zst(ty)); - Constant { + ConstOperand { span: rustc_span::DUMMY_SP, user_ty: None, - literal: ConstantKind::Val(ConstValue::ZeroSized, ty), + const_: Const::Val(ConstValue::ZeroSized, ty), } } } diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs index 243cb463560..abde6a47e83 100644 --- a/compiler/rustc_mir_transform/src/required_consts.rs +++ b/compiler/rustc_mir_transform/src/required_consts.rs @@ -1,27 +1,27 @@ use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Constant, ConstantKind, Location}; +use rustc_middle::mir::{Const, ConstOperand, Location}; use rustc_middle::ty::ConstKind; pub struct RequiredConstsVisitor<'a, 'tcx> { - required_consts: &'a mut Vec<Constant<'tcx>>, + required_consts: &'a mut Vec<ConstOperand<'tcx>>, } impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { - pub fn new(required_consts: &'a mut Vec<Constant<'tcx>>) -> Self { + pub fn new(required_consts: &'a mut Vec<ConstOperand<'tcx>>) -> Self { RequiredConstsVisitor { required_consts } } } impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> { - fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) { - let literal = constant.literal; - match literal { - ConstantKind::Ty(c) => match c.kind() { + fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _: Location) { + let const_ = constant.const_; + match const_ { + Const::Ty(c) => match c.kind() { ConstKind::Param(_) | ConstKind::Error(_) | ConstKind::Value(_) => {} _ => bug!("only ConstKind::Param/Value should be encountered here, got {:#?}", c), }, - ConstantKind::Unevaluated(..) => self.required_consts.push(*constant), - ConstantKind::Val(..) => {} + Const::Unevaluated(..) => self.required_consts.push(*constant), + Const::Val(..) => {} } } } diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 23442f8b97b..065793348e4 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -35,12 +35,12 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { } #[inline] - fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _: Location) { + fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, _: Location) { // We have to use `try_normalize_erasing_regions` here, since it's // possible that we visit impossible-to-satisfy where clauses here, // see #91745 - if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.literal) { - constant.literal = c; + if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.const_) { + constant.const_ = c; } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index e1000d96932..e9895d97dfe 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -497,10 +497,10 @@ impl<'tcx> CloneShimBuilder<'tcx> { // `func == Clone::clone(&ty) -> ty` let func_ty = Ty::new_fn_def(tcx, self.def_id, [ty]); - let func = Operand::Constant(Box::new(Constant { + let func = Operand::Constant(Box::new(ConstOperand { span: self.span, user_ty: None, - literal: ConstantKind::zero_sized(func_ty), + const_: Const::zero_sized(func_ty), })); let ref_loc = self.make_place( @@ -764,10 +764,10 @@ fn build_call_shim<'tcx>( CallKind::Direct(def_id) => { let ty = tcx.type_of(def_id).instantiate_identity(); ( - Operand::Constant(Box::new(Constant { + Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - literal: ConstantKind::zero_sized(ty), + const_: Const::zero_sized(ty), })), rcvr.into_iter().collect::<Vec<_>>(), ) diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 1ff48816986..b508cd1c9cc 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -23,7 +23,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition { TerminatorKind::SwitchInt { discr: Operand::Constant(ref c), ref targets, .. } => { - let constant = c.literal.try_eval_bits(tcx, param_env, c.ty()); + let constant = c.const_.try_eval_bits(tcx, param_env); if let Some(constant) = constant { let target = targets.target_for_value(constant); TerminatorKind::Goto { target } @@ -33,7 +33,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition { } TerminatorKind::Assert { target, cond: Operand::Constant(ref c), expected, .. - } => match c.literal.try_eval_bool(tcx, param_env) { + } => match c.const_.try_eval_bool(tcx, param_env) { Some(v) if v == expected => TerminatorKind::Goto { target }, _ => continue, }, diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index 113ca2fc5ad..1a8cfc41178 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -206,12 +206,12 @@ fn find_branch_value_info<'tcx>( match (left, right) { (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on)) | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => { - let branch_value_ty = branch_value.literal.ty(); + let branch_value_ty = branch_value.const_.ty(); // we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats if !branch_value_ty.is_integral() && !branch_value_ty.is_char() { return None; }; - let branch_value_scalar = branch_value.literal.try_to_scalar()?; + let branch_value_scalar = branch_value.const_.try_to_scalar()?; Some((branch_value_scalar, branch_value_ty, *to_switch_on)) } _ => None, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index c8b72107756..4afa4e597f7 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -746,20 +746,20 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily /// work, as some constants cannot be represented in the type system. #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { - let literal = self.monomorphize(constant.literal); + fn visit_constant(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) { + let const_ = self.monomorphize(constant.const_); let param_env = ty::ParamEnv::reveal_all(); - let val = match literal.eval(self.tcx, param_env, None) { + let val = match const_.eval(self.tcx, param_env, None) { Ok(v) => v, Err(ErrorHandled::Reported(..)) => return, Err(ErrorHandled::TooGeneric(..)) => span_bug!( self.body.source_info(location).span, "collection encountered polymorphic constant: {:?}", - literal + const_ ), }; collect_const_value(self.tcx, val, self.output); - MirVisitor::visit_ty(self, literal.ty(), TyContext::Location(location)); + MirVisitor::visit_ty(self, const_.ty(), TyContext::Location(location)); } fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { @@ -796,7 +796,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { for op in operands { match *op { mir::InlineAsmOperand::SymFn { ref value } => { - let fn_ty = self.monomorphize(value.literal.ty()); + let fn_ty = self.monomorphize(value.const_.ty()); visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output, &[]); } mir::InlineAsmOperand::SymStatic { def_id } => { diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index a8b7a0dbb68..0e85f35fc1b 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -9,13 +9,13 @@ use rustc_hir::{def::DefKind, def_id::DefId, ConstContext}; use rustc_middle::mir::{ self, visit::{TyContext, Visitor}, - Constant, ConstantKind, Local, LocalDecl, Location, + Local, LocalDecl, Location, }; use rustc_middle::query::Providers; use rustc_middle::ty::{ self, visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}, - Const, GenericArgsRef, Ty, TyCtxt, UnusedGenericParams, + GenericArgsRef, Ty, TyCtxt, UnusedGenericParams, }; use rustc_span::symbol::sym; use std::ops::ControlFlow; @@ -261,12 +261,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.super_local_decl(local, local_decl); } - fn visit_constant(&mut self, ct: &Constant<'tcx>, location: Location) { - match ct.literal { - ConstantKind::Ty(c) => { + fn visit_constant(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) { + match ct.const_ { + mir::Const::Ty(c) => { c.visit_with(self); } - ConstantKind::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => { + mir::Const::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => { // Avoid considering `T` unused when constants are of the form: // `<Self as Foo<T>>::foo::promoted[p]` if let Some(p) = promoted { @@ -280,7 +280,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { Visitor::visit_ty(self, ty, TyContext::Location(location)); } - ConstantKind::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)), + mir::Const::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)), } } @@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(level = "debug", skip(self))] - fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { if !c.has_non_region_param() { return ControlFlow::Continue(()); } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 4f8ce99417a..dc0776c5dad 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -407,6 +407,10 @@ passes_invalid_stability = .label = invalid stability version .item = the stability attribute annotates this item +passes_lang_item_fn_with_target_feature = + `{$name}` language item function is not allowed to have `#[target_feature]` + .label = `{$name}` language item function is not allowed to have `#[target_feature]` + passes_lang_item_on_incorrect_target = `{$name}` language item must be applied to a {$expected_target} .label = attribute should be applied to a {$expected_target}, not a {$actual_target} diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2d94354e3e1..12118a0268b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -118,7 +118,7 @@ impl CheckAttrVisitor<'_> { sym::coverage => self.check_coverage(hir_id, attr, span, target), sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target), sym::marker => self.check_marker(hir_id, attr, span, target), - sym::target_feature => self.check_target_feature(hir_id, attr, span, target), + sym::target_feature => self.check_target_feature(hir_id, attr, span, target, attrs), sym::thread_local => self.check_thread_local(attr, span, target), sym::track_caller => { self.check_track_caller(hir_id, attr.span, attrs, span, target) @@ -591,10 +591,36 @@ impl CheckAttrVisitor<'_> { attr: &Attribute, span: Span, target: Target, + attrs: &[Attribute], ) -> bool { match target { - Target::Fn - | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, + Target::Fn => { + // `#[target_feature]` is not allowed in language items. + if let Some((lang_item, _)) = hir::lang_items::extract(attrs) + // Calling functions with `#[target_feature]` is + // not unsafe on WASM, see #84988 + && !self.tcx.sess.target.is_like_wasm + && !self.tcx.sess.opts.actually_rustdoc + { + let hir::Node::Item(item) = self.tcx.hir().get(hir_id) else { + unreachable!(); + }; + let hir::ItemKind::Fn(sig, _, _) = item.kind else { + // target is `Fn` + unreachable!(); + }; + + self.tcx.sess.emit_err(errors::LangItemWithTargetFeature { + attr_span: attr.span, + name: lang_item, + sig_span: sig.span, + }); + false + } else { + true + } + } + Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, // FIXME: #[target_feature] was previously erroneously allowed on statements and some // crates used this, so only emit a warning. Target::Statement => { diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 8437e9a40e2..6d176af8098 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -193,12 +193,12 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { } fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { - let kind = Some(hir::ConstContext::Const); + let kind = Some(hir::ConstContext::Const { inline: false }); self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); } fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) { - let kind = Some(hir::ConstContext::Const); + let kind = Some(hir::ConstContext::Const { inline: true }); self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block)); } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 8b65e301b74..2ec6a0b9241 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -809,6 +809,16 @@ pub struct MissingLangItem { } #[derive(Diagnostic)] +#[diag(passes_lang_item_fn_with_target_feature)] +pub struct LangItemWithTargetFeature { + #[primary_span] + pub attr_span: Span, + pub name: Symbol, + #[label] + pub sig_span: Span, +} + +#[derive(Diagnostic)] #[diag(passes_lang_item_on_incorrect_target, code = "E0718")] pub struct LangItemOnIncorrectTarget { #[primary_span] diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 476394f30cc..7e837243918 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -20,7 +20,8 @@ use rustc_hir::lang_items::{extract, GenericRequirement}; use rustc_hir::{LangItem, LanguageItems, Target}; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::ExternCrate; -use rustc_span::{symbol::kw::Empty, Span}; +use rustc_span::symbol::kw::Empty; +use rustc_span::{sym, Span}; use rustc_middle::query::Providers; @@ -157,7 +158,14 @@ impl<'tcx> LanguageItemCollector<'tcx> { self.tcx.hir().get_by_def_id(item_def_id) { let (actual_num, generics_span) = match kind.generics() { - Some(generics) => (generics.params.len(), generics.span), + Some(generics) => ( + generics + .params + .iter() + .filter(|p| !self.tcx.has_attr(p.def_id, sym::rustc_host)) + .count(), + generics.span, + ), None => (0, *item_span), }; diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 9a0fcbb37a7..30621a135eb 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -92,7 +92,7 @@ where } #[inline(always)] - fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key, DepKind> + fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key> where QueryCtxt<'tcx>: 'a, { @@ -145,7 +145,7 @@ where fn value_from_cycle_error( self, tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo<DepKind>], + cycle: &[QueryInfo], guar: ErrorGuaranteed, ) -> Self::Value { (self.dynamic.value_from_cycle_error)(tcx, cycle, guar) @@ -198,6 +198,8 @@ trait QueryConfigRestored<'tcx> { type RestoredValue; type Config: QueryConfig<QueryCtxt<'tcx>>; + const NAME: &'static &'static str; + fn config(tcx: TyCtxt<'tcx>) -> Self::Config; fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f2fdf066d15..4516708ce17 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -8,7 +8,9 @@ use crate::QueryConfigRestored; use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_data_structures::sync::Lock; use rustc_errors::Diagnostic; + use rustc_index::Idx; +use rustc_middle::dep_graph::dep_kinds; use rustc_middle::dep_graph::{ self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex, }; @@ -53,7 +55,7 @@ impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> { } impl<'tcx> HasDepContext for QueryCtxt<'tcx> { - type DepKind = rustc_middle::dep_graph::DepKind; + type Deps = rustc_middle::dep_graph::DepsType; type DepContext = TyCtxt<'tcx>; #[inline] @@ -78,7 +80,7 @@ impl QueryContext for QueryCtxt<'_> { tls::with_related_context(self.tcx, |icx| icx.query) } - fn try_collect_active_jobs(self) -> Option<QueryMap<DepKind>> { + fn try_collect_active_jobs(self) -> Option<QueryMap> { let mut jobs = QueryMap::default(); for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() { @@ -154,7 +156,7 @@ impl QueryContext for QueryCtxt<'_> { let mut span = None; let mut layout_of_depth = None; if let Some(map) = self.try_collect_active_jobs() { - if let Some((info, depth)) = job.try_find_layout_root(map) { + if let Some((info, depth)) = job.try_find_layout_root(map, dep_kinds::layout_of) { span = Some(info.job.span); layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth }); } @@ -300,7 +302,7 @@ pub(crate) fn create_query_frame< key: K, kind: DepKind, name: &'static str, -) -> QueryStackFrame<DepKind> { +) -> QueryStackFrame { // Avoid calling queries while formatting the description let description = ty::print::with_no_queries!( // Disable visible paths printing for performance reasons. @@ -312,7 +314,7 @@ pub(crate) fn create_query_frame< ); let description = if tcx.sess.verbose() { format!("{description} [{name:?}]") } else { description }; - let span = if kind == dep_graph::DepKind::def_span || with_no_queries() { + let span = if kind == dep_graph::dep_kinds::def_span || with_no_queries() { // The `def_span` query is used to calculate `default_span`, // so exit to avoid infinite recursion. None @@ -320,7 +322,7 @@ pub(crate) fn create_query_frame< Some(key.default_span(tcx)) }; let def_id = key.key_as_def_id(); - let def_kind = if kind == dep_graph::DepKind::opt_def_kind || with_no_queries() { + let def_kind = if kind == dep_graph::dep_kinds::opt_def_kind || with_no_queries() { // Try to avoid infinite recursion. None } else { @@ -329,7 +331,7 @@ pub(crate) fn create_query_frame< let hash = || { tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); - std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher); + kind.as_usize().hash_stable(&mut hcx, &mut hasher); key.hash_stable(&mut hcx, &mut hasher); hasher.finish::<Hash64>() }) @@ -430,8 +432,8 @@ where // hit the cache instead of having to go through `force_from_dep_node`. // This assertion makes sure, we actually keep applying the solution above. debug_assert!( - dep_node.kind != DepKind::codegen_unit, - "calling force_from_dep_node() on DepKind::codegen_unit" + dep_node.kind != dep_kinds::codegen_unit, + "calling force_from_dep_node() on dep_kinds::codegen_unit" ); if let Some(key) = Q::Key::recover(tcx, &dep_node) { @@ -457,6 +459,7 @@ where fingerprint_style, force_from_dep_node: None, try_load_from_on_disk_cache: None, + name: Q::NAME, }; } @@ -470,6 +473,7 @@ where try_load_from_on_disk_cache: Some(|tcx, dep_node| { try_load_from_on_disk_cache(Q::config(tcx), tcx, dep_node) }), + name: Q::NAME, } } @@ -565,7 +569,7 @@ macro_rules! define_queries { DynamicQuery { name: stringify!($name), eval_always: is_eval_always!([$($modifiers)*]), - dep_kind: dep_graph::DepKind::$name, + dep_kind: dep_graph::dep_kinds::$name, handle_cycle_error: handle_cycle_error!([$($modifiers)*]), query_state: offset_of!(QueryStates<'tcx> => $name), query_cache: offset_of!(QueryCaches<'tcx> => $name), @@ -636,6 +640,8 @@ macro_rules! define_queries { { feedable!([$($modifiers)*]) }, >; + const NAME: &'static &'static str = &stringify!($name); + #[inline(always)] fn config(tcx: TyCtxt<'tcx>) -> Self::Config { DynamicConfig { @@ -649,9 +655,9 @@ macro_rules! define_queries { } } - pub fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap<DepKind>) { + pub fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap) { let make_query = |tcx, key| { - let kind = rustc_middle::dep_graph::DepKind::$name; + let kind = rustc_middle::dep_graph::dep_kinds::$name; let name = stringify!($name); $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name) }; @@ -709,7 +715,7 @@ macro_rules! define_queries { // These arrays are used for iteration and can't be indexed by `DepKind`. - const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap<DepKind>)] = + const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap)] = &[$(query_impl::$name::try_collect_active_jobs),*]; const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[ @@ -737,6 +743,7 @@ macro_rules! define_queries { fingerprint_style: FingerprintStyle::Unit, force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)), try_load_from_on_disk_cache: None, + name: &"Null", } } @@ -748,6 +755,7 @@ macro_rules! define_queries { fingerprint_style: FingerprintStyle::Unit, force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)), try_load_from_on_disk_cache: None, + name: &"Red", } } @@ -758,6 +766,7 @@ macro_rules! define_queries { fingerprint_style: FingerprintStyle::Unit, force_from_dep_node: None, try_load_from_on_disk_cache: None, + name: &"TraitSelect", } } @@ -768,6 +777,7 @@ macro_rules! define_queries { fingerprint_style: FingerprintStyle::Opaque, force_from_dep_node: None, try_load_from_on_disk_cache: None, + name: &"CompileCodegenUnit", } } @@ -778,6 +788,7 @@ macro_rules! define_queries { fingerprint_style: FingerprintStyle::Opaque, force_from_dep_node: None, try_load_from_on_disk_cache: None, + name: &"CompileMonoItem", } } diff --git a/compiler/rustc_query_system/src/dep_graph/debug.rs b/compiler/rustc_query_system/src/dep_graph/debug.rs index c2c9600f555..103a6c01bd2 100644 --- a/compiler/rustc_query_system/src/dep_graph/debug.rs +++ b/compiler/rustc_query_system/src/dep_graph/debug.rs @@ -1,6 +1,6 @@ //! Code for debugging the dep-graph. -use super::{DepKind, DepNode, DepNodeIndex}; +use super::{DepNode, DepNodeIndex}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lock; use std::error::Error; @@ -28,7 +28,7 @@ impl DepNodeFilter { } /// Tests whether `node` meets the filter, returning true if so. - pub fn test<K: DepKind>(&self, node: &DepNode<K>) -> bool { + pub fn test(&self, node: &DepNode) -> bool { let debug_str = format!("{node:?}"); self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f)) } @@ -36,14 +36,14 @@ impl DepNodeFilter { /// A filter like `F -> G` where `F` and `G` are valid dep-node /// filters. This can be used to test the source/target independently. -pub struct EdgeFilter<K: DepKind> { +pub struct EdgeFilter { pub source: DepNodeFilter, pub target: DepNodeFilter, - pub index_to_node: Lock<FxHashMap<DepNodeIndex, DepNode<K>>>, + pub index_to_node: Lock<FxHashMap<DepNodeIndex, DepNode>>, } -impl<K: DepKind> EdgeFilter<K> { - pub fn new(test: &str) -> Result<EdgeFilter<K>, Box<dyn Error>> { +impl EdgeFilter { + pub fn new(test: &str) -> Result<EdgeFilter, Box<dyn Error>> { let parts: Vec<_> = test.split("->").collect(); if parts.len() != 2 { Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into()) @@ -57,7 +57,7 @@ impl<K: DepKind> EdgeFilter<K> { } #[cfg(debug_assertions)] - pub fn test(&self, source: &DepNode<K>, target: &DepNode<K>) -> bool { + pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { self.source.test(source) && self.target.test(target) } } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index 39a4cb1b179..17f96896a50 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -42,36 +42,84 @@ //! `DefId` it was computed from. In other cases, too much information gets //! lost during fingerprint computation. -use super::{DepContext, DepKind, FingerprintStyle}; +use super::{DepContext, FingerprintStyle}; use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey}; +use rustc_data_structures::AtomicRef; use rustc_hir::definitions::DefPathHash; use std::fmt; use std::hash::Hash; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -pub struct DepNode<K> { - pub kind: K, +/// This serves as an index into arrays built by `make_dep_kind_array`. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct DepKind { + variant: u16, +} + +impl DepKind { + #[inline] + pub const fn new(variant: u16) -> Self { + Self { variant } + } + + #[inline] + pub const fn as_inner(&self) -> u16 { + self.variant + } + + #[inline] + pub const fn as_usize(&self) -> usize { + self.variant as usize + } +} + +static_assert_size!(DepKind, 2); + +pub fn default_dep_kind_debug(kind: DepKind, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DepKind").field("variant", &kind.variant).finish() +} + +pub static DEP_KIND_DEBUG: AtomicRef<fn(DepKind, &mut fmt::Formatter<'_>) -> fmt::Result> = + AtomicRef::new(&(default_dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + +impl fmt::Debug for DepKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (*DEP_KIND_DEBUG)(*self, f) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct DepNode { + pub kind: DepKind, pub hash: PackedFingerprint, } -impl<K: DepKind> DepNode<K> { +// We keep a lot of `DepNode`s in memory during compilation. It's not +// required that their size stay the same, but we don't want to change +// it inadvertently. This assert just ensures we're aware of any change. +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +static_assert_size!(DepNode, 18); + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +static_assert_size!(DepNode, 24); + +impl DepNode { /// Creates a new, parameterless DepNode. This method will assert /// that the DepNode corresponding to the given DepKind actually /// does not require any parameters. - pub fn new_no_params<Tcx>(tcx: Tcx, kind: K) -> DepNode<K> + pub fn new_no_params<Tcx>(tcx: Tcx, kind: DepKind) -> DepNode where - Tcx: super::DepContext<DepKind = K>, + Tcx: super::DepContext, { debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit); DepNode { kind, hash: Fingerprint::ZERO.into() } } - pub fn construct<Tcx, Key>(tcx: Tcx, kind: K, arg: &Key) -> DepNode<K> + pub fn construct<Tcx, Key>(tcx: Tcx, kind: DepKind, arg: &Key) -> DepNode where - Tcx: super::DepContext<DepKind = K>, + Tcx: super::DepContext, Key: DepNodeParams<Tcx>, { let hash = arg.to_fingerprint(tcx); @@ -93,18 +141,25 @@ impl<K: DepKind> DepNode<K> { /// Construct a DepNode from the given DepKind and DefPathHash. This /// method will assert that the given DepKind actually requires a /// single DefId/DefPathHash parameter. - pub fn from_def_path_hash<Tcx>(tcx: Tcx, def_path_hash: DefPathHash, kind: K) -> Self + pub fn from_def_path_hash<Tcx>(tcx: Tcx, def_path_hash: DefPathHash, kind: DepKind) -> Self where - Tcx: super::DepContext<DepKind = K>, + Tcx: super::DepContext, { debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash); DepNode { kind, hash: def_path_hash.0.into() } } } -impl<K: DepKind> fmt::Debug for DepNode<K> { +pub fn default_dep_node_debug(node: DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DepNode").field("kind", &node.kind).field("hash", &node.hash).finish() +} + +pub static DEP_NODE_DEBUG: AtomicRef<fn(DepNode, &mut fmt::Formatter<'_>) -> fmt::Result> = + AtomicRef::new(&(default_dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + +impl fmt::Debug for DepNode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - K::debug_node(self, f) + (*DEP_NODE_DEBUG)(*self, f) } } @@ -129,7 +184,7 @@ pub trait DepNodeParams<Tcx: DepContext>: fmt::Debug + Sized { /// `fingerprint_style()` is not `FingerprintStyle::Opaque`. /// It is always valid to return `None` here, in which case incremental /// compilation will treat the query as having changed instead of forcing it. - fn recover(tcx: Tcx, dep_node: &DepNode<Tcx::DepKind>) -> Option<Self>; + fn recover(tcx: Tcx, dep_node: &DepNode) -> Option<Self>; } impl<Tcx: DepContext, T> DepNodeParams<Tcx> for T @@ -156,7 +211,7 @@ where } #[inline(always)] - default fn recover(_: Tcx, _: &DepNode<Tcx::DepKind>) -> Option<Self> { + default fn recover(_: Tcx, _: &DepNode) -> Option<Self> { None } } @@ -216,10 +271,13 @@ pub struct DepKindStruct<Tcx: DepContext> { /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` /// is actually a `DefPathHash`, and can therefore just look up the corresponding /// `DefId` in `tcx.def_path_hash_to_def_id`. - pub force_from_dep_node: Option<fn(tcx: Tcx, dep_node: DepNode<Tcx::DepKind>) -> bool>, + pub force_from_dep_node: Option<fn(tcx: Tcx, dep_node: DepNode) -> bool>, /// Invoke a query to put the on-disk cached value in memory. - pub try_load_from_on_disk_cache: Option<fn(Tcx, DepNode<Tcx::DepKind>)>, + pub try_load_from_on_disk_cache: Option<fn(Tcx, DepNode)>, + + /// The name of this dep kind. + pub name: &'static &'static str, } /// A "work product" corresponds to a `.o` (or other) file that we diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index fa54e1a2e6a..c7e92d7b2b2 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -17,7 +17,7 @@ use std::sync::atomic::Ordering::Relaxed; use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; -use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId}; +use super::{DepContext, DepKind, DepNode, Deps, HasDepContext, WorkProductId}; use crate::dep_graph::EdgesVec; use crate::ich::StableHashingContext; use crate::query::{QueryContext, QuerySideEffects}; @@ -26,8 +26,8 @@ use crate::query::{QueryContext, QuerySideEffects}; use {super::debug::EdgeFilter, std::env}; #[derive(Clone)] -pub struct DepGraph<K: DepKind> { - data: Option<Lrc<DepGraphData<K>>>, +pub struct DepGraph<D: Deps> { + data: Option<Lrc<DepGraphData<D>>>, /// This field is used for assigning DepNodeIndices when running in /// non-incremental mode. Even in non-incremental mode we make sure that @@ -74,16 +74,16 @@ impl DepNodeColor { } } -pub struct DepGraphData<K: DepKind> { +pub struct DepGraphData<D: Deps> { /// The new encoding of the dependency graph, optimized for red/green /// tracking. The `current` field is the dependency graph of only the /// current compilation session: We don't merge the previous dep-graph into /// current one anymore, but we do reference shared data to save space. - current: CurrentDepGraph<K>, + current: CurrentDepGraph<D>, /// The dep-graph from the previous compilation session. It contains all /// nodes and edges as well as all fingerprints of nodes that have them. - previous: SerializedDepGraph<K>, + previous: SerializedDepGraph, colors: DepNodeColorMap, @@ -95,12 +95,12 @@ pub struct DepGraphData<K: DepKind> { /// this map. We can later look for and extract that data. previous_work_products: WorkProductMap, - dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>, + dep_node_debug: Lock<FxHashMap<DepNode, String>>, /// Used by incremental compilation tests to assert that /// a particular query result was decoded from disk /// (not just marked green) - debug_loaded_from_disk: Lock<FxHashSet<DepNode<K>>>, + debug_loaded_from_disk: Lock<FxHashSet<DepNode>>, } pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint @@ -112,15 +112,15 @@ where stable_hasher.finish() } -impl<K: DepKind> DepGraph<K> { +impl<D: Deps> DepGraph<D> { pub fn new( profiler: &SelfProfilerRef, - prev_graph: SerializedDepGraph<K>, + prev_graph: SerializedDepGraph, prev_work_products: WorkProductMap, encoder: FileEncoder, record_graph: bool, record_stats: bool, - ) -> DepGraph<K> { + ) -> DepGraph<D> { let prev_graph_node_count = prev_graph.node_count(); let current = CurrentDepGraph::new( @@ -136,7 +136,7 @@ impl<K: DepKind> DepGraph<K> { // Instantiate a dependy-less node only once for anonymous queries. let _green_node_index = current.intern_new_node( profiler, - DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() }, + DepNode { kind: D::DEP_KIND_NULL, hash: current.anon_id_seed.into() }, EdgesVec::new(), Fingerprint::ZERO, ); @@ -146,7 +146,7 @@ impl<K: DepKind> DepGraph<K> { let (red_node_index, red_node_prev_index_and_color) = current.intern_node( profiler, &prev_graph, - DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() }, + DepNode { kind: D::DEP_KIND_RED, hash: Fingerprint::ZERO.into() }, EdgesVec::new(), None, false, @@ -181,12 +181,12 @@ impl<K: DepKind> DepGraph<K> { } } - pub fn new_disabled() -> DepGraph<K> { + pub fn new_disabled() -> DepGraph<D> { DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) } } #[inline] - pub fn data(&self) -> Option<&DepGraphData<K>> { + pub fn data(&self) -> Option<&DepGraphData<D>> { self.data.as_deref() } @@ -196,7 +196,7 @@ impl<K: DepKind> DepGraph<K> { self.data.is_some() } - pub fn with_query(&self, f: impl Fn(&DepGraphQuery<K>)) { + pub fn with_query(&self, f: impl Fn(&DepGraphQuery)) { if let Some(data) = &self.data { data.current.encoder.borrow().with_query(f) } @@ -204,7 +204,7 @@ impl<K: DepKind> DepGraph<K> { pub fn assert_ignored(&self) { if let Some(..) = self.data { - K::read_deps(|task_deps| { + D::read_deps(|task_deps| { assert_matches!( task_deps, TaskDepsRef::Ignore, @@ -218,7 +218,7 @@ impl<K: DepKind> DepGraph<K> { where OP: FnOnce() -> R, { - K::with_deps(TaskDepsRef::Ignore, op) + D::with_deps(TaskDepsRef::Ignore, op) } /// Used to wrap the deserialization of a query result from disk, @@ -271,13 +271,13 @@ impl<K: DepKind> DepGraph<K> { where OP: FnOnce() -> R, { - K::with_deps(TaskDepsRef::Forbid, op) + D::with_deps(TaskDepsRef::Forbid, op) } #[inline(always)] - pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>( + pub fn with_task<Ctxt: HasDepContext<Deps = D>, A: Debug, R>( &self, - key: DepNode<K>, + key: DepNode, cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, @@ -289,10 +289,10 @@ impl<K: DepKind> DepGraph<K> { } } - pub fn with_anon_task<Tcx: DepContext<DepKind = K>, OP, R>( + pub fn with_anon_task<Tcx: DepContext<Deps = D>, OP, R>( &self, cx: Tcx, - dep_kind: K, + dep_kind: DepKind, op: OP, ) -> (R, DepNodeIndex) where @@ -305,7 +305,7 @@ impl<K: DepKind> DepGraph<K> { } } -impl<K: DepKind> DepGraphData<K> { +impl<D: Deps> DepGraphData<D> { /// Starts a new dep-graph task. Dep-graph tasks are specified /// using a free function (`task`) and **not** a closure -- this /// is intentional because we want to exercise tight control over @@ -334,9 +334,9 @@ impl<K: DepKind> DepGraphData<K> { /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html #[inline(always)] - pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>( + pub fn with_task<Ctxt: HasDepContext<Deps = D>, A: Debug, R>( &self, - key: DepNode<K>, + key: DepNode, cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, @@ -354,7 +354,7 @@ impl<K: DepKind> DepGraphData<K> { - dep-node: {key:?}" ); - let with_deps = |task_deps| K::with_deps(task_deps, || task(cx, arg)); + let with_deps = |task_deps| D::with_deps(task_deps, || task(cx, arg)); let (result, edges) = if cx.dep_context().is_eval_always(key.kind) { (with_deps(TaskDepsRef::EvalAlways), EdgesVec::new()) } else { @@ -402,10 +402,10 @@ impl<K: DepKind> DepGraphData<K> { /// Executes something within an "anonymous" task, that is, a task the /// `DepNode` of which is determined by the list of inputs it read from. - pub fn with_anon_task<Tcx: DepContext<DepKind = K>, OP, R>( + pub fn with_anon_task<Tcx: DepContext<Deps = D>, OP, R>( &self, cx: Tcx, - dep_kind: K, + dep_kind: DepKind, op: OP, ) -> (R, DepNodeIndex) where @@ -414,7 +414,7 @@ impl<K: DepKind> DepGraphData<K> { debug_assert!(!cx.is_eval_always(dep_kind)); let task_deps = Lock::new(TaskDeps::default()); - let result = K::with_deps(TaskDepsRef::Allow(&task_deps), op); + let result = D::with_deps(TaskDepsRef::Allow(&task_deps), op); let task_deps = task_deps.into_inner(); let task_deps = task_deps.reads; @@ -461,11 +461,11 @@ impl<K: DepKind> DepGraphData<K> { } } -impl<K: DepKind> DepGraph<K> { +impl<D: Deps> DepGraph<D> { #[inline] pub fn read_index(&self, dep_node_index: DepNodeIndex) { if let Some(ref data) = self.data { - K::read_deps(|task_deps| { + D::read_deps(|task_deps| { let mut task_deps = match task_deps { TaskDepsRef::Allow(deps) => deps.lock(), TaskDepsRef::EvalAlways => { @@ -532,9 +532,9 @@ impl<K: DepKind> DepGraph<K> { /// FIXME: If the code is changed enough for this node to be marked before requiring the /// caller's node, we suppose that those changes will be enough to mark this node red and /// force a recomputation using the "normal" way. - pub fn with_feed_task<Ctxt: DepContext<DepKind = K>, A: Debug, R: Debug>( + pub fn with_feed_task<Ctxt: DepContext<Deps = D>, A: Debug, R: Debug>( &self, - node: DepNode<K>, + node: DepNode, cx: Ctxt, key: A, result: &R, @@ -573,7 +573,7 @@ impl<K: DepKind> DepGraph<K> { } let mut edges = EdgesVec::new(); - K::read_deps(|task_deps| match task_deps { + D::read_deps(|task_deps| match task_deps { TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()), TaskDepsRef::EvalAlways => { edges.push(DepNodeIndex::FOREVER_RED_NODE); @@ -623,9 +623,9 @@ impl<K: DepKind> DepGraph<K> { } } -impl<K: DepKind> DepGraphData<K> { +impl<D: Deps> DepGraphData<D> { #[inline] - pub fn dep_node_index_of_opt(&self, dep_node: &DepNode<K>) -> Option<DepNodeIndex> { + pub fn dep_node_index_of_opt(&self, dep_node: &DepNode) -> Option<DepNodeIndex> { if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) { self.current.prev_index_to_index.lock()[prev_index] } else { @@ -634,11 +634,11 @@ impl<K: DepKind> DepGraphData<K> { } #[inline] - pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool { + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { self.dep_node_index_of_opt(dep_node).is_some() } - fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> { + fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> { if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) { self.colors.get(prev_index) } else { @@ -660,18 +660,18 @@ impl<K: DepKind> DepGraphData<K> { } #[inline] - pub fn prev_node_of(&self, prev_index: SerializedDepNodeIndex) -> DepNode<K> { + pub fn prev_node_of(&self, prev_index: SerializedDepNodeIndex) -> DepNode { self.previous.index_to_node(prev_index) } - pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode<K>) { + pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode) { self.debug_loaded_from_disk.lock().insert(dep_node); } } -impl<K: DepKind> DepGraph<K> { +impl<D: Deps> DepGraph<D> { #[inline] - pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool { + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { self.data.as_ref().is_some_and(|data| data.dep_node_exists(dep_node)) } @@ -687,12 +687,12 @@ impl<K: DepKind> DepGraph<K> { &self.data.as_ref().unwrap().previous_work_products } - pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode<K>) -> bool { + pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode) -> bool { self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node) } #[inline(always)] - pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen: F) + pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode, debug_str_gen: F) where F: FnOnce() -> String, { @@ -705,11 +705,11 @@ impl<K: DepKind> DepGraph<K> { dep_node_debug.borrow_mut().insert(dep_node, debug_str); } - pub fn dep_node_debug_str(&self, dep_node: DepNode<K>) -> Option<String> { + pub fn dep_node_debug_str(&self, dep_node: DepNode) -> Option<String> { self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned() } - fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> { + fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> { if let Some(ref data) = self.data { return data.node_color(dep_node); } @@ -717,25 +717,25 @@ impl<K: DepKind> DepGraph<K> { None } - pub fn try_mark_green<Qcx: QueryContext<DepKind = K>>( + pub fn try_mark_green<Qcx: QueryContext<Deps = D>>( &self, qcx: Qcx, - dep_node: &DepNode<K>, + dep_node: &DepNode, ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { self.data().and_then(|data| data.try_mark_green(qcx, dep_node)) } } -impl<K: DepKind> DepGraphData<K> { +impl<D: Deps> DepGraphData<D> { /// Try to mark a node index for the node dep_node. /// /// A node will have an index, when it's already been marked green, or when we can mark it /// green. This function will mark the current task as a reader of the specified node, when /// a node index can be found for that node. - pub fn try_mark_green<Qcx: QueryContext<DepKind = K>>( + pub fn try_mark_green<Qcx: QueryContext<Deps = D>>( &self, qcx: Qcx, - dep_node: &DepNode<K>, + dep_node: &DepNode, ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind)); @@ -757,11 +757,11 @@ impl<K: DepKind> DepGraphData<K> { } #[instrument(skip(self, qcx, parent_dep_node_index, frame), level = "debug")] - fn try_mark_parent_green<Qcx: QueryContext<DepKind = K>>( + fn try_mark_parent_green<Qcx: QueryContext<Deps = D>>( &self, qcx: Qcx, parent_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode<K>, + dep_node: &DepNode, frame: Option<&MarkFrame<'_>>, ) -> Option<()> { let dep_dep_node_color = self.colors.get(parent_dep_node_index); @@ -845,11 +845,11 @@ impl<K: DepKind> DepGraphData<K> { /// Try to mark a dep-node which existed in the previous compilation session as green. #[instrument(skip(self, qcx, prev_dep_node_index, frame), level = "debug")] - fn try_mark_previous_green<Qcx: QueryContext<DepKind = K>>( + fn try_mark_previous_green<Qcx: QueryContext<Deps = D>>( &self, qcx: Qcx, prev_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode<K>, + dep_node: &DepNode, frame: Option<&MarkFrame<'_>>, ) -> Option<DepNodeIndex> { let frame = MarkFrame { index: prev_dep_node_index, parent: frame }; @@ -916,7 +916,7 @@ impl<K: DepKind> DepGraphData<K> { /// This may be called concurrently on multiple threads for the same dep node. #[cold] #[inline(never)] - fn emit_side_effects<Qcx: QueryContext<DepKind = K>>( + fn emit_side_effects<Qcx: QueryContext<Deps = D>>( &self, qcx: Qcx, dep_node_index: DepNodeIndex, @@ -940,16 +940,16 @@ impl<K: DepKind> DepGraphData<K> { } } -impl<K: DepKind> DepGraph<K> { +impl<D: Deps> DepGraph<D> { /// Returns true if the given node has been marked as red during the /// current compilation session. Used in various assertions - pub fn is_red(&self, dep_node: &DepNode<K>) -> bool { + pub fn is_red(&self, dep_node: &DepNode) -> bool { self.node_color(dep_node) == Some(DepNodeColor::Red) } /// Returns true if the given node has been marked as green during the /// current compilation session. Used in various assertions - pub fn is_green(&self, dep_node: &DepNode<K>) -> bool { + pub fn is_green(&self, dep_node: &DepNode) -> bool { self.node_color(dep_node).is_some_and(|c| c.is_green()) } @@ -961,7 +961,7 @@ impl<K: DepKind> DepGraph<K> { /// /// This method will only load queries that will end up in the disk cache. /// Other queries will not be executed. - pub fn exec_cache_promotions<Tcx: DepContext<DepKind = K>>(&self, tcx: Tcx) { + pub fn exec_cache_promotions<Tcx: DepContext>(&self, tcx: Tcx) { let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion"); let data = self.data.as_ref().unwrap(); @@ -1076,9 +1076,9 @@ rustc_index::newtype_index! { /// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When /// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index` /// first, and `data` second. -pub(super) struct CurrentDepGraph<K: DepKind> { - encoder: Steal<GraphEncoder<K>>, - new_node_to_index: Sharded<FxHashMap<DepNode<K>, DepNodeIndex>>, +pub(super) struct CurrentDepGraph<D: Deps> { + encoder: Steal<GraphEncoder<D>>, + new_node_to_index: Sharded<FxHashMap<DepNode, DepNodeIndex>>, prev_index_to_index: Lock<IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>>, /// This is used to verify that fingerprints do not change between the creation of a node @@ -1089,7 +1089,7 @@ pub(super) struct CurrentDepGraph<K: DepKind> { /// Used to trap when a specific edge is added to the graph. /// This is used for debug purposes and is only active with `debug_assertions`. #[cfg(debug_assertions)] - forbidden_edge: Option<EdgeFilter<K>>, + forbidden_edge: Option<EdgeFilter>, /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of /// their edges. This has the beneficial side-effect that multiple anonymous @@ -1116,14 +1116,14 @@ pub(super) struct CurrentDepGraph<K: DepKind> { node_intern_event_id: Option<EventId>, } -impl<K: DepKind> CurrentDepGraph<K> { +impl<D: Deps> CurrentDepGraph<D> { fn new( profiler: &SelfProfilerRef, prev_graph_node_count: usize, encoder: FileEncoder, record_graph: bool, record_stats: bool, - ) -> CurrentDepGraph<K> { + ) -> Self { use std::time::{SystemTime, UNIX_EPOCH}; let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); @@ -1178,7 +1178,7 @@ impl<K: DepKind> CurrentDepGraph<K> { } #[cfg(debug_assertions)] - fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode<K>, fingerprint: Fingerprint) { + fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode, fingerprint: Fingerprint) { if let Some(forbidden_edge) = &self.forbidden_edge { forbidden_edge.index_to_node.lock().insert(dep_node_index, key); } @@ -1192,7 +1192,7 @@ impl<K: DepKind> CurrentDepGraph<K> { fn intern_new_node( &self, profiler: &SelfProfilerRef, - key: DepNode<K>, + key: DepNode, edges: EdgesVec, current_fingerprint: Fingerprint, ) -> DepNodeIndex { @@ -1215,8 +1215,8 @@ impl<K: DepKind> CurrentDepGraph<K> { fn intern_node( &self, profiler: &SelfProfilerRef, - prev_graph: &SerializedDepGraph<K>, - key: DepNode<K>, + prev_graph: &SerializedDepGraph, + key: DepNode, edges: EdgesVec, fingerprint: Option<Fingerprint>, print_status: bool, @@ -1289,7 +1289,7 @@ impl<K: DepKind> CurrentDepGraph<K> { fn promote_node_and_deps_to_current( &self, profiler: &SelfProfilerRef, - prev_graph: &SerializedDepGraph<K>, + prev_graph: &SerializedDepGraph, prev_index: SerializedDepNodeIndex, ) -> DepNodeIndex { self.debug_assert_not_in_new_nodes(prev_graph, prev_index); @@ -1317,7 +1317,7 @@ impl<K: DepKind> CurrentDepGraph<K> { #[inline] fn debug_assert_not_in_new_nodes( &self, - prev_graph: &SerializedDepGraph<K>, + prev_graph: &SerializedDepGraph, prev_index: SerializedDepNodeIndex, ) { let node = &prev_graph.index_to_node(prev_index); @@ -1329,11 +1329,11 @@ impl<K: DepKind> CurrentDepGraph<K> { } #[derive(Debug, Clone, Copy)] -pub enum TaskDepsRef<'a, K: DepKind> { +pub enum TaskDepsRef<'a> { /// New dependencies can be added to the /// `TaskDeps`. This is used when executing a 'normal' query /// (no `eval_always` modifier) - Allow(&'a Lock<TaskDeps<K>>), + Allow(&'a Lock<TaskDeps>), /// This is used when executing an `eval_always` query. We don't /// need to track dependencies for a query that's always /// re-executed -- but we need to know that this is an `eval_always` @@ -1350,15 +1350,15 @@ pub enum TaskDepsRef<'a, K: DepKind> { } #[derive(Debug)] -pub struct TaskDeps<K: DepKind> { +pub struct TaskDeps { #[cfg(debug_assertions)] - node: Option<DepNode<K>>, + node: Option<DepNode>, reads: EdgesVec, read_set: FxHashSet<DepNodeIndex>, - phantom_data: PhantomData<DepNode<K>>, + phantom_data: PhantomData<DepNode>, } -impl<K: DepKind> Default for TaskDeps<K> { +impl Default for TaskDeps { fn default() -> Self { Self { #[cfg(debug_assertions)] @@ -1410,10 +1410,7 @@ impl DepNodeColorMap { #[inline(never)] #[cold] -pub(crate) fn print_markframe_trace<K: DepKind>( - graph: &DepGraph<K>, - frame: Option<&MarkFrame<'_>>, -) { +pub(crate) fn print_markframe_trace<D: Deps>(graph: &DepGraph<D>, frame: Option<&MarkFrame<'_>>) { let data = graph.data.as_ref().unwrap(); eprintln!("there was a panic while trying to force a dep node"); diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 272028d35bf..624ae680a8f 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -1,11 +1,11 @@ pub mod debug; -mod dep_node; +pub mod dep_node; mod edges; mod graph; mod query; mod serialized; -pub use dep_node::{DepKindStruct, DepNode, DepNodeParams, WorkProductId}; +pub use dep_node::{DepKind, DepKindStruct, DepNode, DepNodeParams, WorkProductId}; pub use edges::EdgesVec; pub use graph::{ hash_result, DepGraph, DepGraphData, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, @@ -16,22 +16,20 @@ pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use crate::ich::StableHashingContext; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_serialize::{opaque::FileEncoder, Encodable}; use rustc_session::Session; -use std::hash::Hash; -use std::{fmt, panic}; +use std::panic; use self::graph::{print_markframe_trace, MarkFrame}; pub trait DepContext: Copy { - type DepKind: self::DepKind; + type Deps: Deps; /// Create a hashing context for hashing new results. fn with_stable_hashing_context<R>(self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R; /// Access the DepGraph. - fn dep_graph(&self) -> &DepGraph<Self::DepKind>; + fn dep_graph(&self) -> &DepGraph<Self::Deps>; /// Access the profiler. fn profiler(&self) -> &SelfProfilerRef; @@ -39,10 +37,10 @@ pub trait DepContext: Copy { /// Access the compiler session. fn sess(&self) -> &Session; - fn dep_kind_info(&self, dep_node: Self::DepKind) -> &DepKindStruct<Self>; + fn dep_kind_info(&self, dep_node: DepKind) -> &DepKindStruct<Self>; #[inline(always)] - fn fingerprint_style(self, kind: Self::DepKind) -> FingerprintStyle { + fn fingerprint_style(self, kind: DepKind) -> FingerprintStyle { let data = self.dep_kind_info(kind); if data.is_anon { return FingerprintStyle::Opaque; @@ -52,18 +50,14 @@ pub trait DepContext: Copy { #[inline(always)] /// Return whether this kind always require evaluation. - fn is_eval_always(self, kind: Self::DepKind) -> bool { + fn is_eval_always(self, kind: DepKind) -> bool { self.dep_kind_info(kind).is_eval_always } /// Try to force a dep node to execute and see if it's green. #[inline] #[instrument(skip(self, frame), level = "debug")] - fn try_force_from_dep_node( - self, - dep_node: DepNode<Self::DepKind>, - frame: Option<&MarkFrame<'_>>, - ) -> bool { + fn try_force_from_dep_node(self, dep_node: DepNode, frame: Option<&MarkFrame<'_>>) -> bool { let cb = self.dep_kind_info(dep_node.kind); if let Some(f) = cb.force_from_dep_node { if let Err(value) = panic::catch_unwind(panic::AssertUnwindSafe(|| { @@ -81,7 +75,7 @@ pub trait DepContext: Copy { } /// Load data from the on-disk cache. - fn try_load_from_on_disk_cache(self, dep_node: DepNode<Self::DepKind>) { + fn try_load_from_on_disk_cache(self, dep_node: DepNode) { let cb = self.dep_kind_info(dep_node.kind); if let Some(f) = cb.try_load_from_on_disk_cache { f(self, dep_node) @@ -89,15 +83,37 @@ pub trait DepContext: Copy { } } +pub trait Deps { + /// Execute the operation with provided dependencies. + fn with_deps<OP, R>(deps: TaskDepsRef<'_>, op: OP) -> R + where + OP: FnOnce() -> R; + + /// Access dependencies from current implicit context. + fn read_deps<OP>(op: OP) + where + OP: for<'a> FnOnce(TaskDepsRef<'a>); + + /// We use this for most things when incr. comp. is turned off. + const DEP_KIND_NULL: DepKind; + + /// We use this to create a forever-red node. + const DEP_KIND_RED: DepKind; + + /// This is the highest value a `DepKind` can have. It's used during encoding to + /// pack information into the unused bits. + const DEP_KIND_MAX: u16; +} + pub trait HasDepContext: Copy { - type DepKind: self::DepKind; - type DepContext: self::DepContext<DepKind = Self::DepKind>; + type Deps: self::Deps; + type DepContext: self::DepContext<Deps = Self::Deps>; fn dep_context(&self) -> &Self::DepContext; } impl<T: DepContext> HasDepContext for T { - type DepKind = T::DepKind; + type Deps = T::Deps; type DepContext = Self; fn dep_context(&self) -> &Self::DepContext { @@ -106,7 +122,7 @@ impl<T: DepContext> HasDepContext for T { } impl<T: HasDepContext, Q: Copy> HasDepContext for (T, Q) { - type DepKind = T::DepKind; + type Deps = T::Deps; type DepContext = T::DepContext; fn dep_context(&self) -> &Self::DepContext { @@ -138,31 +154,3 @@ impl FingerprintStyle { } } } - -/// Describe the different families of dependency nodes. -pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static { - /// DepKind to use when incr. comp. is turned off. - const NULL: Self; - - /// DepKind to use to create the initial forever-red node. - const RED: Self; - - /// Implementation of `std::fmt::Debug` for `DepNode`. - fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result; - - /// Execute the operation with provided dependencies. - fn with_deps<OP, R>(deps: TaskDepsRef<'_, Self>, op: OP) -> R - where - OP: FnOnce() -> R; - - /// Access dependencies from current implicit context. - fn read_deps<OP>(op: OP) - where - OP: for<'a> FnOnce(TaskDepsRef<'a, Self>); - - fn from_u16(u: u16) -> Self; - - fn to_u16(self) -> u16; - - const MAX: u16; -} diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index 5cbc6bf8f8a..5969e5fbe98 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -2,16 +2,16 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::implementation::{Direction, Graph, NodeIndex, INCOMING}; use rustc_index::IndexVec; -use super::{DepKind, DepNode, DepNodeIndex}; +use super::{DepNode, DepNodeIndex}; -pub struct DepGraphQuery<K> { - pub graph: Graph<DepNode<K>, ()>, - pub indices: FxHashMap<DepNode<K>, NodeIndex>, +pub struct DepGraphQuery { + pub graph: Graph<DepNode, ()>, + pub indices: FxHashMap<DepNode, NodeIndex>, pub dep_index_to_index: IndexVec<DepNodeIndex, Option<NodeIndex>>, } -impl<K: DepKind> DepGraphQuery<K> { - pub fn new(prev_node_count: usize) -> DepGraphQuery<K> { +impl DepGraphQuery { + pub fn new(prev_node_count: usize) -> DepGraphQuery { let node_count = prev_node_count + prev_node_count / 4; let edge_count = 6 * node_count; @@ -22,7 +22,7 @@ impl<K: DepKind> DepGraphQuery<K> { DepGraphQuery { graph, indices, dep_index_to_index } } - pub fn push(&mut self, index: DepNodeIndex, node: DepNode<K>, edges: &[DepNodeIndex]) { + pub fn push(&mut self, index: DepNodeIndex, node: DepNode, edges: &[DepNodeIndex]) { let source = self.graph.add_node(node); self.dep_index_to_index.insert(index, source); self.indices.insert(node, source); @@ -37,11 +37,11 @@ impl<K: DepKind> DepGraphQuery<K> { } } - pub fn nodes(&self) -> Vec<&DepNode<K>> { + pub fn nodes(&self) -> Vec<&DepNode> { self.graph.all_nodes().iter().map(|n| &n.data).collect() } - pub fn edges(&self) -> Vec<(&DepNode<K>, &DepNode<K>)> { + pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { self.graph .all_edges() .iter() @@ -50,7 +50,7 @@ impl<K: DepKind> DepGraphQuery<K> { .collect() } - fn reachable_nodes(&self, node: &DepNode<K>, direction: Direction) -> Vec<&DepNode<K>> { + fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { if let Some(&index) = self.indices.get(node) { self.graph.depth_traverse(index, direction).map(|s| self.graph.node_data(s)).collect() } else { @@ -59,7 +59,7 @@ impl<K: DepKind> DepGraphQuery<K> { } /// All nodes that can reach `node`. - pub fn transitive_predecessors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> { + pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { self.reachable_nodes(node, INCOMING) } } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 07eb10cba02..fcf46be6e6f 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -36,7 +36,7 @@ //! store it directly after the header with leb128. use super::query::DepGraphQuery; -use super::{DepKind, DepNode, DepNodeIndex}; +use super::{DepKind, DepNode, DepNodeIndex, Deps}; use crate::dep_graph::EdgesVec; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::PackedFingerprint; @@ -70,9 +70,9 @@ const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2; /// Data for use when recompiling the **current crate**. #[derive(Debug)] -pub struct SerializedDepGraph<K: DepKind> { +pub struct SerializedDepGraph { /// The set of all DepNodes in the graph - nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>, + nodes: IndexVec<SerializedDepNodeIndex, DepNode>, /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to /// the DepNode at the same index in the nodes vector. fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>, @@ -88,7 +88,7 @@ pub struct SerializedDepGraph<K: DepKind> { index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>, } -impl<K: DepKind> Default for SerializedDepGraph<K> { +impl Default for SerializedDepGraph { fn default() -> Self { SerializedDepGraph { nodes: Default::default(), @@ -100,7 +100,7 @@ impl<K: DepKind> Default for SerializedDepGraph<K> { } } -impl<K: DepKind> SerializedDepGraph<K> { +impl SerializedDepGraph { #[inline] pub fn edge_targets_from( &self, @@ -134,13 +134,13 @@ impl<K: DepKind> SerializedDepGraph<K> { } #[inline] - pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> { + pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { self.nodes[dep_node_index] } #[inline] - pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> { - self.index.get(dep_node.kind.to_u16() as usize)?.get(&dep_node.hash).cloned() + pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> { + self.index.get(dep_node.kind.as_usize())?.get(&dep_node.hash).cloned() } #[inline] @@ -184,11 +184,9 @@ fn mask(bits: usize) -> usize { usize::MAX >> ((std::mem::size_of::<usize>() * 8) - bits) } -impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>> - for SerializedDepGraph<K> -{ +impl SerializedDepGraph { #[instrument(level = "debug", skip(d))] - fn decode(d: &mut MemDecoder<'a>) -> SerializedDepGraph<K> { + pub fn decode<D: Deps>(d: &mut MemDecoder<'_>) -> SerializedDepGraph { // The last 16 bytes are the node count and edge count. debug!("position: {:?}", d.position()); let (node_count, edge_count) = @@ -217,14 +215,14 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>> // least (34 byte header + 1 byte len + 64 bytes edge data), which is ~1%. A 2-byte leb128 // length is about the same fractional overhead and it amortizes for yet greater lengths. let mut edge_list_data = Vec::with_capacity( - graph_bytes - node_count * std::mem::size_of::<SerializedNodeHeader<K>>(), + graph_bytes - node_count * std::mem::size_of::<SerializedNodeHeader<D>>(), ); for _index in 0..node_count { // Decode the header for this edge; the header packs together as many of the fixed-size // fields as possible to limit the number of times we update decoder state. let node_header = - SerializedNodeHeader::<K> { bytes: d.read_array(), _marker: PhantomData }; + SerializedNodeHeader::<D> { bytes: d.read_array(), _marker: PhantomData }; let _i: SerializedDepNodeIndex = nodes.push(node_header.node()); debug_assert_eq!(_i.index(), _index); @@ -256,12 +254,12 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>> edge_list_data.extend(&[0u8; DEP_NODE_PAD]); // Read the number of each dep kind and use it to create an hash map with a suitable size. - let mut index: Vec<_> = (0..(K::MAX as usize + 1)) + let mut index: Vec<_> = (0..(D::DEP_KIND_MAX + 1)) .map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default())) .collect(); for (idx, node) in nodes.iter_enumerated() { - index[node.kind.to_u16() as usize].insert(node.hash, idx); + index[node.kind.as_usize()].insert(node.hash, idx); } SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index } @@ -276,20 +274,20 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>> /// * The `DepKind`'s discriminant (a u16, but not all bits are used...) /// * The byte width of the encoded edges for this node /// * In whatever bits remain, the length of the edge list for this node, if it fits -struct SerializedNodeHeader<K> { +struct SerializedNodeHeader<D> { // 2 bytes for the DepNode // 16 for Fingerprint in DepNode // 16 for Fingerprint in NodeInfo bytes: [u8; 34], - _marker: PhantomData<K>, + _marker: PhantomData<D>, } // The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only // to make the implementation of `SerializedNodeHeader` simpler. -struct Unpacked<K> { +struct Unpacked { len: Option<usize>, bytes_per_index: usize, - kind: K, + kind: DepKind, hash: PackedFingerprint, fingerprint: Fingerprint, } @@ -301,20 +299,20 @@ struct Unpacked<K> { // 0..M length of the edge // M..M+N bytes per index // M+N..16 kind -impl<K: DepKind> SerializedNodeHeader<K> { - const TOTAL_BITS: usize = std::mem::size_of::<K>() * 8; +impl<D: Deps> SerializedNodeHeader<D> { + const TOTAL_BITS: usize = std::mem::size_of::<DepKind>() * 8; const LEN_BITS: usize = Self::TOTAL_BITS - Self::KIND_BITS - Self::WIDTH_BITS; const WIDTH_BITS: usize = DEP_NODE_WIDTH_BITS; - const KIND_BITS: usize = Self::TOTAL_BITS - K::MAX.leading_zeros() as usize; + const KIND_BITS: usize = Self::TOTAL_BITS - D::DEP_KIND_MAX.leading_zeros() as usize; const MAX_INLINE_LEN: usize = (u16::MAX as usize >> (Self::TOTAL_BITS - Self::LEN_BITS)) - 1; #[inline] - fn new(node_info: &NodeInfo<K>) -> Self { + fn new(node_info: &NodeInfo) -> Self { debug_assert_eq!(Self::TOTAL_BITS, Self::LEN_BITS + Self::WIDTH_BITS + Self::KIND_BITS); let NodeInfo { node, fingerprint, edges } = node_info; - let mut head = node.kind.to_u16(); + let mut head = node.kind.as_inner(); let free_bytes = edges.max_index().leading_zeros() as usize / 8; let bytes_per_index = (DEP_NODE_SIZE - free_bytes).saturating_sub(1); @@ -347,7 +345,7 @@ impl<K: DepKind> SerializedNodeHeader<K> { } #[inline] - fn unpack(&self) -> Unpacked<K> { + fn unpack(&self) -> Unpacked { let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap()); let hash = self.bytes[2..18].try_into().unwrap(); let fingerprint = self.bytes[18..].try_into().unwrap(); @@ -359,7 +357,7 @@ impl<K: DepKind> SerializedNodeHeader<K> { Unpacked { len: len.checked_sub(1), bytes_per_index: bytes_per_index as usize + 1, - kind: DepKind::from_u16(kind), + kind: DepKind::new(kind), hash: Fingerprint::from_le_bytes(hash).into(), fingerprint: Fingerprint::from_le_bytes(fingerprint), } @@ -381,7 +379,7 @@ impl<K: DepKind> SerializedNodeHeader<K> { } #[inline] - fn node(&self) -> DepNode<K> { + fn node(&self) -> DepNode { let Unpacked { kind, hash, .. } = self.unpack(); DepNode { kind, hash } } @@ -395,15 +393,15 @@ impl<K: DepKind> SerializedNodeHeader<K> { } #[derive(Debug)] -struct NodeInfo<K: DepKind> { - node: DepNode<K>, +struct NodeInfo { + node: DepNode, fingerprint: Fingerprint, edges: EdgesVec, } -impl<K: DepKind> Encodable<FileEncoder> for NodeInfo<K> { - fn encode(&self, e: &mut FileEncoder) { - let header = SerializedNodeHeader::new(self); +impl NodeInfo { + fn encode<D: Deps>(&self, e: &mut FileEncoder) { + let header = SerializedNodeHeader::<D>::new(self); e.write_array(header.bytes); if header.len().is_none() { @@ -420,41 +418,43 @@ impl<K: DepKind> Encodable<FileEncoder> for NodeInfo<K> { } } -struct Stat<K: DepKind> { - kind: K, +struct Stat { + kind: DepKind, node_counter: u64, edge_counter: u64, } -struct EncoderState<K: DepKind> { +struct EncoderState<D: Deps> { encoder: FileEncoder, total_node_count: usize, total_edge_count: usize, - stats: Option<FxHashMap<K, Stat<K>>>, + stats: Option<FxHashMap<DepKind, Stat>>, /// Stores the number of times we've encoded each dep kind. kind_stats: Vec<u32>, + marker: PhantomData<D>, } -impl<K: DepKind> EncoderState<K> { +impl<D: Deps> EncoderState<D> { fn new(encoder: FileEncoder, record_stats: bool) -> Self { Self { encoder, total_edge_count: 0, total_node_count: 0, stats: record_stats.then(FxHashMap::default), - kind_stats: iter::repeat(0).take(K::MAX as usize + 1).collect(), + kind_stats: iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(), + marker: PhantomData, } } fn encode_node( &mut self, - node: &NodeInfo<K>, - record_graph: &Option<Lock<DepGraphQuery<K>>>, + node: &NodeInfo, + record_graph: &Option<Lock<DepGraphQuery>>, ) -> DepNodeIndex { let index = DepNodeIndex::new(self.total_node_count); self.total_node_count += 1; - self.kind_stats[node.node.kind.to_u16() as usize] += 1; + self.kind_stats[node.node.kind.as_usize()] += 1; let edge_count = node.edges.len(); self.total_edge_count += edge_count; @@ -475,12 +475,19 @@ impl<K: DepKind> EncoderState<K> { } let encoder = &mut self.encoder; - node.encode(encoder); + node.encode::<D>(encoder); index } fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { - let Self { mut encoder, total_node_count, total_edge_count, stats: _, kind_stats } = self; + let Self { + mut encoder, + total_node_count, + total_edge_count, + stats: _, + kind_stats, + marker: _, + } = self; let node_count = total_node_count.try_into().unwrap(); let edge_count = total_edge_count.try_into().unwrap(); @@ -506,12 +513,12 @@ impl<K: DepKind> EncoderState<K> { } } -pub struct GraphEncoder<K: DepKind> { - status: Lock<EncoderState<K>>, - record_graph: Option<Lock<DepGraphQuery<K>>>, +pub struct GraphEncoder<D: Deps> { + status: Lock<EncoderState<D>>, + record_graph: Option<Lock<DepGraphQuery>>, } -impl<K: DepKind + Encodable<FileEncoder>> GraphEncoder<K> { +impl<D: Deps> GraphEncoder<D> { pub fn new( encoder: FileEncoder, prev_node_count: usize, @@ -523,7 +530,7 @@ impl<K: DepKind + Encodable<FileEncoder>> GraphEncoder<K> { GraphEncoder { status, record_graph } } - pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery<K>)) { + pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery)) { if let Some(record_graph) = &self.record_graph { f(&record_graph.lock()) } @@ -584,7 +591,7 @@ impl<K: DepKind + Encodable<FileEncoder>> GraphEncoder<K> { pub(crate) fn send( &self, profiler: &SelfProfilerRef, - node: DepNode<K>, + node: DepNode, fingerprint: Fingerprint, edges: EdgesVec, ) -> DepNodeIndex { diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index d14c6315dc1..c025fac2631 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -1,6 +1,6 @@ //! Query configuration and description traits. -use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex}; +use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex}; use crate::error::HandleCycleError; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; @@ -27,7 +27,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy { fn format_value(self) -> fn(&Self::Value) -> String; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState<Self::Key, Qcx::DepKind> + fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState<Self::Key> where Qcx: 'a; @@ -57,7 +57,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy { fn value_from_cycle_error( self, tcx: Qcx::DepContext, - cycle: &[QueryInfo<Qcx::DepKind>], + cycle: &[QueryInfo], guar: ErrorGuaranteed, ) -> Self::Value; @@ -66,12 +66,12 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy { fn depth_limit(self) -> bool; fn feedable(self) -> bool; - fn dep_kind(self) -> Qcx::DepKind; + fn dep_kind(self) -> DepKind; fn handle_cycle_error(self) -> HandleCycleError; fn hash_result(self) -> HashResult<Self::Value>; // Just here for convenience and checking that the key matches the kind, don't override this. - fn construct_dep_node(self, tcx: Qcx::DepContext, key: &Self::Key) -> DepNode<Qcx::DepKind> { + fn construct_dep_node(self, tcx: Qcx::DepContext, key: &Self::Key) -> DepNode { DepNode::construct(tcx, self.dep_kind(), key) } } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 6c01dc3c00d..2e9ebde296c 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -1,9 +1,8 @@ -use crate::dep_graph::DepKind; +use crate::dep_graph::DepContext; use crate::error::CycleStack; use crate::query::plumbing::CycleError; +use crate::query::DepKind; use crate::query::{QueryContext, QueryStackFrame}; -use core::marker::PhantomData; - use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, Level, @@ -30,48 +29,48 @@ use { /// Represents a span and a query key. #[derive(Clone, Debug)] -pub struct QueryInfo<D: DepKind> { +pub struct QueryInfo { /// The span corresponding to the reason for which this query was required. pub span: Span, - pub query: QueryStackFrame<D>, + pub query: QueryStackFrame, } -pub type QueryMap<D> = FxHashMap<QueryJobId, QueryJobInfo<D>>; +pub type QueryMap = FxHashMap<QueryJobId, QueryJobInfo>; /// A value uniquely identifying an active query job. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct QueryJobId(pub NonZeroU64); impl QueryJobId { - fn query<D: DepKind>(self, map: &QueryMap<D>) -> QueryStackFrame<D> { + fn query(self, map: &QueryMap) -> QueryStackFrame { map.get(&self).unwrap().query.clone() } #[cfg(parallel_compiler)] - fn span<D: DepKind>(self, map: &QueryMap<D>) -> Span { + fn span(self, map: &QueryMap) -> Span { map.get(&self).unwrap().job.span } #[cfg(parallel_compiler)] - fn parent<D: DepKind>(self, map: &QueryMap<D>) -> Option<QueryJobId> { + fn parent(self, map: &QueryMap) -> Option<QueryJobId> { map.get(&self).unwrap().job.parent } #[cfg(parallel_compiler)] - fn latch<D: DepKind>(self, map: &QueryMap<D>) -> Option<&QueryLatch<D>> { + fn latch(self, map: &QueryMap) -> Option<&QueryLatch> { map.get(&self).unwrap().job.latch.as_ref() } } #[derive(Clone)] -pub struct QueryJobInfo<D: DepKind> { - pub query: QueryStackFrame<D>, - pub job: QueryJob<D>, +pub struct QueryJobInfo { + pub query: QueryStackFrame, + pub job: QueryJob, } /// Represents an active query job. #[derive(Clone)] -pub struct QueryJob<D: DepKind> { +pub struct QueryJob { pub id: QueryJobId, /// The span corresponding to the reason for which this query was required. @@ -82,11 +81,10 @@ pub struct QueryJob<D: DepKind> { /// The latch that is used to wait on this job. #[cfg(parallel_compiler)] - latch: Option<QueryLatch<D>>, - spooky: core::marker::PhantomData<D>, + latch: Option<QueryLatch>, } -impl<D: DepKind> QueryJob<D> { +impl QueryJob { /// Creates a new query job. #[inline] pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self { @@ -96,12 +94,11 @@ impl<D: DepKind> QueryJob<D> { parent, #[cfg(parallel_compiler)] latch: None, - spooky: PhantomData, } } #[cfg(parallel_compiler)] - pub(super) fn latch(&mut self) -> QueryLatch<D> { + pub(super) fn latch(&mut self) -> QueryLatch { if self.latch.is_none() { self.latch = Some(QueryLatch::new()); } @@ -124,12 +121,12 @@ impl<D: DepKind> QueryJob<D> { } impl QueryJobId { - pub(super) fn find_cycle_in_stack<D: DepKind>( + pub(super) fn find_cycle_in_stack( &self, - query_map: QueryMap<D>, + query_map: QueryMap, current_job: &Option<QueryJobId>, span: Span, - ) -> CycleError<D> { + ) -> CycleError { // Find the waitee amongst `current_job` parents let mut cycle = Vec::new(); let mut current_job = Option::clone(current_job); @@ -163,18 +160,18 @@ impl QueryJobId { #[cold] #[inline(never)] - pub fn try_find_layout_root<D: DepKind>( + pub fn try_find_layout_root( &self, - query_map: QueryMap<D>, - ) -> Option<(QueryJobInfo<D>, usize)> { + query_map: QueryMap, + layout_of_kind: DepKind, + ) -> Option<(QueryJobInfo, usize)> { let mut last_layout = None; let mut current_id = Some(*self); let mut depth = 0; while let Some(id) = current_id { let info = query_map.get(&id).unwrap(); - // FIXME: This string comparison should probably not be done. - if format!("{:?}", info.query.dep_kind) == "layout_of" { + if info.query.dep_kind == layout_of_kind { depth += 1; last_layout = Some((info.clone(), depth)); } @@ -185,15 +182,15 @@ impl QueryJobId { } #[cfg(parallel_compiler)] -struct QueryWaiter<D: DepKind> { +struct QueryWaiter { query: Option<QueryJobId>, condvar: Condvar, span: Span, - cycle: Mutex<Option<CycleError<D>>>, + cycle: Mutex<Option<CycleError>>, } #[cfg(parallel_compiler)] -impl<D: DepKind> QueryWaiter<D> { +impl QueryWaiter { fn notify(&self, registry: &rayon_core::Registry) { rayon_core::mark_unblocked(registry); self.condvar.notify_one(); @@ -201,19 +198,19 @@ impl<D: DepKind> QueryWaiter<D> { } #[cfg(parallel_compiler)] -struct QueryLatchInfo<D: DepKind> { +struct QueryLatchInfo { complete: bool, - waiters: Vec<Arc<QueryWaiter<D>>>, + waiters: Vec<Arc<QueryWaiter>>, } #[cfg(parallel_compiler)] #[derive(Clone)] -pub(super) struct QueryLatch<D: DepKind> { - info: Arc<Mutex<QueryLatchInfo<D>>>, +pub(super) struct QueryLatch { + info: Arc<Mutex<QueryLatchInfo>>, } #[cfg(parallel_compiler)] -impl<D: DepKind> QueryLatch<D> { +impl QueryLatch { fn new() -> Self { QueryLatch { info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), @@ -221,11 +218,7 @@ impl<D: DepKind> QueryLatch<D> { } /// Awaits for the query job to complete. - pub(super) fn wait_on( - &self, - query: Option<QueryJobId>, - span: Span, - ) -> Result<(), CycleError<D>> { + pub(super) fn wait_on(&self, query: Option<QueryJobId>, span: Span) -> Result<(), CycleError> { let waiter = Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() }); self.wait_on_inner(&waiter); @@ -240,7 +233,7 @@ impl<D: DepKind> QueryLatch<D> { } /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, waiter: &Arc<QueryWaiter<D>>) { + fn wait_on_inner(&self, waiter: &Arc<QueryWaiter>) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -274,7 +267,7 @@ impl<D: DepKind> QueryLatch<D> { /// Removes a single waiter from the list of waiters. /// This is used to break query cycles. - fn extract_waiter(&self, waiter: usize) -> Arc<QueryWaiter<D>> { + fn extract_waiter(&self, waiter: usize) -> Arc<QueryWaiter> { let mut info = self.info.lock(); debug_assert!(!info.complete); // Remove the waiter from the list of waiters @@ -296,14 +289,9 @@ type Waiter = (QueryJobId, usize); /// required information to resume the waiter. /// If all `visit` calls returns None, this function also returns None. #[cfg(parallel_compiler)] -fn visit_waiters<F, D>( - query_map: &QueryMap<D>, - query: QueryJobId, - mut visit: F, -) -> Option<Option<Waiter>> +fn visit_waiters<F>(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option<Option<Waiter>> where F: FnMut(Span, QueryJobId) -> Option<Option<Waiter>>, - D: DepKind, { // Visit the parent query which is a non-resumable waiter since it's on the same stack if let Some(parent) = query.parent(query_map) { @@ -332,8 +320,8 @@ where /// If a cycle is detected, this initial value is replaced with the span causing /// the cycle. #[cfg(parallel_compiler)] -fn cycle_check<D: DepKind>( - query_map: &QueryMap<D>, +fn cycle_check( + query_map: &QueryMap, query: QueryJobId, span: Span, stack: &mut Vec<(Span, QueryJobId)>, @@ -373,8 +361,8 @@ fn cycle_check<D: DepKind>( /// from `query` without going through any of the queries in `visited`. /// This is achieved with a depth first search. #[cfg(parallel_compiler)] -fn connected_to_root<D: DepKind>( - query_map: &QueryMap<D>, +fn connected_to_root( + query_map: &QueryMap, query: QueryJobId, visited: &mut FxHashSet<QueryJobId>, ) -> bool { @@ -396,10 +384,9 @@ fn connected_to_root<D: DepKind>( // Deterministically pick an query from a list #[cfg(parallel_compiler)] -fn pick_query<'a, T, F, D>(query_map: &QueryMap<D>, queries: &'a [T], f: F) -> &'a T +fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T where F: Fn(&T) -> (Span, QueryJobId), - D: DepKind, { // Deterministically pick an entry point // FIXME: Sort this instead @@ -423,10 +410,10 @@ where /// If a cycle was not found, the starting query is removed from `jobs` and /// the function returns false. #[cfg(parallel_compiler)] -fn remove_cycle<D: DepKind>( - query_map: &QueryMap<D>, +fn remove_cycle( + query_map: &QueryMap, jobs: &mut Vec<QueryJobId>, - wakelist: &mut Vec<Arc<QueryWaiter<D>>>, + wakelist: &mut Vec<Arc<QueryWaiter>>, ) -> bool { let mut visited = FxHashSet::default(); let mut stack = Vec::new(); @@ -528,7 +515,7 @@ fn remove_cycle<D: DepKind>( /// There may be multiple cycles involved in a deadlock, so this searches /// all active queries for cycles before finally resuming all the waiters at once. #[cfg(parallel_compiler)] -pub fn deadlock<D: DepKind>(query_map: QueryMap<D>, registry: &rayon_core::Registry) { +pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) { let on_panic = defer(|| { eprintln!("deadlock handler panicked, aborting process"); process::abort(); @@ -566,9 +553,9 @@ pub fn deadlock<D: DepKind>(query_map: QueryMap<D>, registry: &rayon_core::Regis #[inline(never)] #[cold] -pub(crate) fn report_cycle<'a, D: DepKind>( +pub(crate) fn report_cycle<'a>( sess: &'a Session, - CycleError { usage, cycle: stack }: &CycleError<D>, + CycleError { usage, cycle: stack }: &CycleError, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { assert!(!stack.is_empty()); @@ -655,8 +642,10 @@ pub fn print_query_stack<Qcx: QueryContext>( if let Some(ref mut file) = file { let _ = writeln!( file, - "#{} [{:?}] {}", - count_total, query_info.query.dep_kind, query_info.query.description + "#{} [{}] {}", + count_total, + qcx.dep_context().dep_kind_info(query_info.query.dep_kind).name, + query_info.query.description ); } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index f7619d75be7..05dee9f12db 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -28,27 +28,27 @@ use thin_vec::ThinVec; /// /// This is mostly used in case of cycles for error reporting. #[derive(Clone, Debug)] -pub struct QueryStackFrame<D: DepKind> { +pub struct QueryStackFrame { pub description: String, span: Option<Span>, pub def_id: Option<DefId>, pub def_kind: Option<DefKind>, pub ty_adt_id: Option<DefId>, - pub dep_kind: D, + pub dep_kind: DepKind, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. #[cfg(parallel_compiler)] hash: Hash64, } -impl<D: DepKind> QueryStackFrame<D> { +impl QueryStackFrame { #[inline] pub fn new( description: String, span: Option<Span>, def_id: Option<DefId>, def_kind: Option<DefKind>, - dep_kind: D, + dep_kind: DepKind, ty_adt_id: Option<DefId>, _hash: impl FnOnce() -> Hash64, ) -> Self { @@ -106,7 +106,7 @@ pub trait QueryContext: HasDepContext { /// Get the query information from the TLS context. fn current_query_job(self) -> Option<QueryJobId>; - fn try_collect_active_jobs(self) -> Option<QueryMap<Self::DepKind>>; + fn try_collect_active_jobs(self) -> Option<QueryMap>; /// Load side effects associated to the node in the previous session. fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 07db15e6d8b..f93edffca79 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -2,8 +2,8 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams}; -use crate::dep_graph::{DepGraphData, HasDepContext}; +use crate::dep_graph::DepGraphData; +use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams}; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; #[cfg(parallel_compiler)] @@ -30,24 +30,23 @@ use thin_vec::ThinVec; use super::QueryConfig; -pub struct QueryState<K, D: DepKind> { - active: Sharded<FxHashMap<K, QueryResult<D>>>, +pub struct QueryState<K> { + active: Sharded<FxHashMap<K, QueryResult>>, } /// Indicates the state of a query for a given key in a query map. -enum QueryResult<D: DepKind> { +enum QueryResult { /// An already executing query. The query job can be used to await for its completion. - Started(QueryJob<D>), + Started(QueryJob), /// The query panicked. Queries trying to wait on this will raise a fatal error which will /// silently panic. Poisoned, } -impl<K, D> QueryState<K, D> +impl<K> QueryState<K> where K: Eq + Hash + Copy + Debug, - D: DepKind, { pub fn all_inactive(&self) -> bool { self.active.lock_shards().all(|shard| shard.is_empty()) @@ -56,8 +55,8 @@ where pub fn try_collect_active_jobs<Qcx: Copy>( &self, qcx: Qcx, - make_query: fn(Qcx, K) -> QueryStackFrame<D>, - jobs: &mut QueryMap<D>, + make_query: fn(Qcx, K) -> QueryStackFrame, + jobs: &mut QueryMap, ) -> Option<()> { let mut active = Vec::new(); @@ -82,25 +81,25 @@ where } } -impl<K, D: DepKind> Default for QueryState<K, D> { - fn default() -> QueryState<K, D> { +impl<K> Default for QueryState<K> { + fn default() -> QueryState<K> { QueryState { active: Default::default() } } } /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. -struct JobOwner<'tcx, K, D: DepKind> +struct JobOwner<'tcx, K> where K: Eq + Hash + Copy, { - state: &'tcx QueryState<K, D>, + state: &'tcx QueryState<K>, key: K, } #[cold] #[inline(never)] -fn mk_cycle<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError<Qcx::DepKind>) -> Q::Value +fn mk_cycle<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError) -> Q::Value where Q: QueryConfig<Qcx>, Qcx: QueryContext, @@ -112,7 +111,7 @@ where fn handle_cycle_error<Q, Qcx>( query: Q, qcx: Qcx, - cycle_error: &CycleError<Qcx::DepKind>, + cycle_error: &CycleError, mut error: DiagnosticBuilder<'_, ErrorGuaranteed>, ) -> Q::Value where @@ -137,7 +136,7 @@ where } } -impl<'tcx, K, D: DepKind> JobOwner<'tcx, K, D> +impl<'tcx, K> JobOwner<'tcx, K> where K: Eq + Hash + Copy, { @@ -169,10 +168,9 @@ where } } -impl<'tcx, K, D> Drop for JobOwner<'tcx, K, D> +impl<'tcx, K> Drop for JobOwner<'tcx, K> where K: Eq + Hash + Copy, - D: DepKind, { #[inline(never)] #[cold] @@ -195,10 +193,10 @@ where } #[derive(Clone)] -pub(crate) struct CycleError<D: DepKind> { +pub(crate) struct CycleError { /// The query and related span that uses the cycle. - pub usage: Option<(Span, QueryStackFrame<D>)>, - pub cycle: Vec<QueryInfo<D>>, + pub usage: Option<(Span, QueryStackFrame)>, + pub cycle: Vec<QueryInfo>, } /// Checks if the query is already computed and in the cache. @@ -248,7 +246,7 @@ fn wait_for_query<Q, Qcx>( qcx: Qcx, span: Span, key: Q::Key, - latch: QueryLatch<Qcx::DepKind>, + latch: QueryLatch, current: Option<QueryJobId>, ) -> (Q::Value, Option<DepNodeIndex>) where @@ -296,7 +294,7 @@ fn try_execute_query<Q, Qcx, const INCR: bool>( qcx: Qcx, span: Span, key: Q::Key, - dep_node: Option<DepNode<Qcx::DepKind>>, + dep_node: Option<DepNode>, ) -> (Q::Value, Option<DepNodeIndex>) where Q: QueryConfig<Qcx>, @@ -364,10 +362,10 @@ where fn execute_job<Q, Qcx, const INCR: bool>( query: Q, qcx: Qcx, - state: &QueryState<Q::Key, Qcx::DepKind>, + state: &QueryState<Q::Key>, key: Q::Key, id: QueryJobId, - dep_node: Option<DepNode<Qcx::DepKind>>, + dep_node: Option<DepNode>, ) -> (Q::Value, Option<DepNodeIndex>) where Q: QueryConfig<Qcx>, @@ -474,9 +472,9 @@ where fn execute_job_incr<Q, Qcx>( query: Q, qcx: Qcx, - dep_graph_data: &DepGraphData<Qcx::DepKind>, + dep_graph_data: &DepGraphData<Qcx::Deps>, key: Q::Key, - mut dep_node_opt: Option<DepNode<Qcx::DepKind>>, + mut dep_node_opt: Option<DepNode>, job_id: QueryJobId, ) -> (Q::Value, DepNodeIndex) where @@ -540,10 +538,10 @@ where #[inline(always)] fn try_load_from_disk_and_cache_in_memory<Q, Qcx>( query: Q, - dep_graph_data: &DepGraphData<Qcx::DepKind>, + dep_graph_data: &DepGraphData<Qcx::Deps>, qcx: Qcx, key: &Q::Key, - dep_node: &DepNode<Qcx::DepKind>, + dep_node: &DepNode, ) -> Option<(Q::Value, DepNodeIndex)> where Q: QueryConfig<Qcx>, @@ -637,7 +635,7 @@ where #[instrument(skip(tcx, dep_graph_data, result, hash_result, format_value), level = "debug")] pub(crate) fn incremental_verify_ich<Tcx, V>( tcx: Tcx, - dep_graph_data: &DepGraphData<Tcx::DepKind>, + dep_graph_data: &DepGraphData<Tcx::Deps>, result: &V, prev_index: SerializedDepNodeIndex, hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>, @@ -730,7 +728,7 @@ fn ensure_must_run<Q, Qcx>( qcx: Qcx, key: &Q::Key, check_cache: bool, -) -> (bool, Option<DepNode<Qcx::DepKind>>) +) -> (bool, Option<DepNode>) where Q: QueryConfig<Qcx>, Qcx: QueryContext, @@ -821,12 +819,8 @@ where Some(result) } -pub fn force_query<Q, Qcx>( - query: Q, - qcx: Qcx, - key: Q::Key, - dep_node: DepNode<<Qcx as HasDepContext>::DepKind>, -) where +pub fn force_query<Q, Qcx>(query: Q, qcx: Qcx, key: Q::Key, dep_node: DepNode) +where Q: QueryConfig<Qcx>, Qcx: QueryContext, { diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs index 07c28fdb73b..8848fda9da3 100644 --- a/compiler/rustc_query_system/src/values.rs +++ b/compiler/rustc_query_system/src/values.rs @@ -1,14 +1,14 @@ use rustc_span::ErrorGuaranteed; -use crate::dep_graph::{DepContext, DepKind}; +use crate::dep_graph::DepContext; use crate::query::QueryInfo; -pub trait Value<Tcx: DepContext, D: DepKind>: Sized { - fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>], guar: ErrorGuaranteed) -> Self; +pub trait Value<Tcx: DepContext>: Sized { + fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self; } -impl<Tcx: DepContext, T, D: DepKind> Value<Tcx, D> for T { - default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>], _guar: ErrorGuaranteed) -> T { +impl<Tcx: DepContext, T> Value<Tcx> for T { + default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> 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. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 5a6def1958b..23f2be632b2 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -20,7 +20,7 @@ use std::collections::BTreeMap; use std::collections::hash_map::DefaultHasher; use std::hash::Hasher; -use std::num::NonZeroUsize; +use std::num::{IntErrorKind, NonZeroUsize}; use std::path::PathBuf; use std::str; @@ -387,7 +387,7 @@ mod desc { "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`"; pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; pub const parse_unpretty: &str = "`string` or `string=string`"; - pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0"; + pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; pub const parse_trait_solver: &str = "one of the supported solver modes (`classic`, `next`, or `next-coherence`)"; pub const parse_lto: &str = @@ -986,10 +986,16 @@ mod parse { pub(crate) fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool { match v { - Some(s) => { - *slot = s.parse().ok(); - slot.is_some() - } + Some(s) => match s.parse() { + Ok(val) => { + *slot = Some(val); + true + } + Err(e) => { + *slot = None; + e.kind() == &IntErrorKind::Zero + } + }, None => { *slot = NonZeroUsize::new(1); true @@ -1846,7 +1852,8 @@ written to standard error output)"), trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED], "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"), treat_err_as_bug: Option<NonZeroUsize> = (None, parse_treat_err_as_bug, [TRACKED], - "treat error number `val` that occurs as bug"), + "treat the `val`th error that occurs as bug (default if not specified: 0 - don't treat errors as bugs. \ + default if specified without a value: 1 - treat the first error as bug)"), trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED], "in diagnostics, use heuristics to shorten paths referring to items"), tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED], diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 93b5b9654d3..ad5f17cab6c 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -14,8 +14,8 @@ use crate::stable_mir::ty::{ }; use crate::stable_mir::{self, CompilerError, Context}; use rustc_hir as hir; +use rustc_middle::mir; use rustc_middle::mir::interpret::{alloc_range, AllocId}; -use rustc_middle::mir::{self, ConstantKind}; use rustc_middle::ty::{self, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_span::ErrorGuaranteed; @@ -539,14 +539,14 @@ impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { } } -impl<'tcx> Stable<'tcx> for mir::Constant<'tcx> { +impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> { type T = stable_mir::mir::Constant; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { stable_mir::mir::Constant { span: self.span.stable(tables), user_ty: self.user_ty.map(|u| u.as_usize()).or(None), - literal: self.literal.stable(tables), + literal: self.const_.stable(tables), } } } @@ -1247,13 +1247,13 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef { } } -impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> { +impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { type T = stable_mir::ty::Const; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { match *self { - ConstantKind::Ty(c) => c.stable(tables), - ConstantKind::Unevaluated(unev_const, ty) => stable_mir::ty::Const { + mir::Const::Ty(c) => c.stable(tables), + mir::Const::Unevaluated(unev_const, ty) => stable_mir::ty::Const { literal: stable_mir::ty::ConstantKind::Unevaluated( stable_mir::ty::UnevaluatedConst { def: tables.const_def(unev_const.def), @@ -1263,7 +1263,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> { ), ty: tables.intern_ty(ty), }, - ConstantKind::Val(val, ty) => stable_mir::ty::Const { + mir::Const::Val(val, ty) => stable_mir::ty::Const { literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( ty, val, tables, )), diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 77457c8daaa..d1f2c1b27fd 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -118,7 +118,7 @@ fn encode_const<'tcx>( // bool value false is encoded as 0 and true as 1. match c.ty().kind() { ty::Int(ity) => { - let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty()); + let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all()); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; if val < 0 { s.push('n'); @@ -126,7 +126,7 @@ fn encode_const<'tcx>( let _ = write!(s, "{val}"); } ty::Uint(_) => { - let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty()); + let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all()); let _ = write!(s, "{val}"); } ty::Bool => { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 2550570af65..e9a7d0be4b4 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -594,7 +594,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { self = ty.print(self)?; - let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ty); + let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all()); // Negative integer values are mangled using `n` as a "sign prefix". if let ty::Int(ity) = ty.kind() { diff --git a/compiler/rustc_target/src/spec/hurd_base.rs b/compiler/rustc_target/src/spec/hurd_base.rs new file mode 100644 index 00000000000..76f8223c0e4 --- /dev/null +++ b/compiler/rustc_target/src/spec/hurd_base.rs @@ -0,0 +1,15 @@ +use crate::spec::{cvs, RelroLevel, TargetOptions}; + +pub fn opts() -> TargetOptions { + TargetOptions { + os: "hurd".into(), + dynamic_linking: true, + families: cvs!["unix"], + has_rpath: true, + position_independent_executables: true, + relro_level: RelroLevel::Full, + has_thread_local: true, + crt_static_respected: true, + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/hurd_gnu_base.rs b/compiler/rustc_target/src/spec/hurd_gnu_base.rs new file mode 100644 index 00000000000..b9cf26d9380 --- /dev/null +++ b/compiler/rustc_target/src/spec/hurd_gnu_base.rs @@ -0,0 +1,5 @@ +use crate::spec::TargetOptions; + +pub fn opts() -> TargetOptions { + TargetOptions { env: "gnu".into(), ..super::hurd_base::opts() } +} diff --git a/compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs new file mode 100644 index 00000000000..29f80360138 --- /dev/null +++ b/compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs @@ -0,0 +1,19 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; + +pub fn target() -> Target { + let mut base = super::hurd_gnu_base::opts(); + base.cpu = "pentiumpro".into(); + base.max_atomic_width = Some(64); + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); + base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + + Target { + llvm_target: "i686-unknown-hurd-gnu".into(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ + f64:32:64-f80:32-n8:16:32-S128" + .into(), + arch: "x86".into(), + options: base, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8aa72797a0d..60fe98e5045 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -71,6 +71,8 @@ mod freebsd_base; mod fuchsia_base; mod haiku_base; mod hermit_base; +mod hurd_base; +mod hurd_gnu_base; mod illumos_base; mod l4re_base; mod linux_base; @@ -1367,6 +1369,8 @@ supported_targets! { ("i686-unknown-haiku", i686_unknown_haiku), ("x86_64-unknown-haiku", x86_64_unknown_haiku), + ("i686-unknown-hurd-gnu", i686_unknown_hurd_gnu), + ("aarch64-apple-darwin", aarch64_apple_darwin), ("x86_64-apple-darwin", x86_64_apple_darwin), ("x86_64h-apple-darwin", x86_64h_apple_darwin), diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 16de518e8e0..728d0fc1ae7 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -8,7 +8,7 @@ use cache::ProvisionalCache; use rustc_data_structures::fx::FxHashSet; use rustc_index::Idx; use rustc_index::IndexVec; -use rustc_middle::dep_graph::DepKind; +use rustc_middle::dep_graph::dep_kinds; use rustc_middle::traits::solve::inspect::CacheHit; use rustc_middle::traits::solve::CacheData; use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult}; @@ -287,7 +287,7 @@ impl<'tcx> SearchGraph<'tcx> { // Everything that affects the `result` should be performed within this // `with_anon_task` closure. let ((final_entry, result), dep_node) = - tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || { + tcx.dep_graph.with_anon_task(tcx, dep_kinds::TraitSelect, || { // When we encounter a coinductive cycle, we have to fetch the // result of that cycle while we are still computing it. Because // of this we continuously recompute the cycle until the result diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 7d754cbafa3..d3e0d3b8b18 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -987,6 +987,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause); + self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref); // Return early if the trait is Debug or Display and the invocation // originates within a standard library macro, because the output diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 4086db2ab55..d645dc033b8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -104,7 +104,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => { self.describe_generator(*body_id).or_else(|| { Some(match sig.header { - hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async function", + hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => { + "an async function" + } _ => "a function", }) }) @@ -118,7 +120,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .. }) => self.describe_generator(*body_id).or_else(|| { Some(match sig.header { - hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async method", + hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => "an async method", _ => "a method", }) }), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index a08ebe5a9ea..cd1dadde1ba 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -414,6 +414,12 @@ pub trait TypeErrCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, cause: &ObligationCause<'tcx>, ); + + fn suggest_desugaring_async_fn_in_trait( + &self, + err: &mut Diagnostic, + trait_ref: ty::PolyTraitRef<'tcx>, + ); } fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) { @@ -2711,6 +2717,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::IfExpressionWithNoElse | ObligationCauseCode::MainFunctionType | ObligationCauseCode::StartFunctionType + | ObligationCauseCode::LangFunctionType(_) | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression @@ -4100,6 +4107,136 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }); } } + + fn suggest_desugaring_async_fn_in_trait( + &self, + err: &mut Diagnostic, + trait_ref: ty::PolyTraitRef<'tcx>, + ) { + // Don't suggest if RTN is active -- we should prefer a where-clause bound instead. + if self.tcx.features().return_type_notation { + return; + } + + let trait_def_id = trait_ref.def_id(); + + // Only suggest specifying auto traits + if !self.tcx.trait_is_auto(trait_def_id) { + return; + } + + // Look for an RPITIT + let ty::Alias(ty::Projection, alias_ty) = trait_ref.self_ty().skip_binder().kind() else { + return; + }; + let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) = + self.tcx.opt_rpitit_info(alias_ty.def_id) + else { + return; + }; + + let auto_trait = self.tcx.def_path_str(trait_def_id); + // ... which is a local function + let Some(fn_def_id) = fn_def_id.as_local() else { + // If it's not local, we can at least mention that the method is async, if it is. + if self.tcx.asyncness(fn_def_id).is_async() { + err.span_note( + self.tcx.def_span(fn_def_id), + format!( + "`{}::{}` is an `async fn` in trait, which does not \ + automatically imply that its future is `{auto_trait}`", + alias_ty.trait_ref(self.tcx), + self.tcx.item_name(fn_def_id) + ), + ); + } + return; + }; + let Some(hir::Node::TraitItem(item)) = self.tcx.hir().find_by_def_id(fn_def_id) else { + return; + }; + + // ... whose signature is `async` (i.e. this is an AFIT) + let (sig, body) = item.expect_fn(); + let hir::IsAsync::Async(async_span) = sig.header.asyncness else { + return; + }; + let Ok(async_span) = + self.tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace()) + else { + return; + }; + let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) = + sig.decl.output + else { + // This should never happen, but let's not ICE. + return; + }; + + // Check that this is *not* a nested `impl Future` RPIT in an async fn + // (i.e. `async fn foo() -> impl Future`) + if def.owner_id.to_def_id() != opaque_def_id { + return; + } + + let future = self.tcx.hir().item(*def).expect_opaque_ty(); + let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else { + // `async fn` should always lower to a lang item bound... but don't ICE. + return; + }; + let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) = + generics.bindings.get(0).map(|binding| binding.kind) + else { + // Also should never happen. + return; + }; + + let function_name = self.tcx.def_path_str(fn_def_id); + + let mut sugg = if future_output_ty.span.is_empty() { + vec![ + (async_span, String::new()), + ( + future_output_ty.span, + format!(" -> impl std::future::Future<Output = ()> + {auto_trait}"), + ), + ] + } else { + vec![ + ( + future_output_ty.span.shrink_to_lo(), + "impl std::future::Future<Output = ".to_owned(), + ), + (future_output_ty.span.shrink_to_hi(), format!("> + {auto_trait}")), + (async_span, String::new()), + ] + }; + + // If there's a body, we also need to wrap it in `async {}` + if let hir::TraitFn::Provided(body) = body { + let body = self.tcx.hir().body(*body); + let body_span = body.value.span; + let body_span_without_braces = + body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1)); + if body_span_without_braces.is_empty() { + sugg.push((body_span_without_braces, " async {} ".to_owned())); + } else { + sugg.extend([ + (body_span_without_braces.shrink_to_lo(), "async {".to_owned()), + (body_span_without_braces.shrink_to_hi(), "} ".to_owned()), + ]); + } + } + + err.multipart_suggestion( + format!( + "`{auto_trait}` can be made part of the associated future's \ + guarantees for all implementations of `{function_name}`" + ), + sugg, + Applicability::MachineApplicable, + ); + } } /// Add a hint to add a missing borrow or remove an unnecessary one. diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 24d31633850..dcf41c3774f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -35,7 +35,8 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::traits::TraitObligation; -use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; +use rustc_middle::dep_graph::dep_kinds; +use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -1435,7 +1436,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { OP: FnOnce(&mut Self) -> R, { let (result, dep_node) = - self.tcx().dep_graph.with_anon_task(self.tcx(), DepKind::TraitSelect, || op(self)); + self.tcx().dep_graph.with_anon_task(self.tcx(), dep_kinds::TraitSelect, || op(self)); self.tcx().dep_graph.read_index(dep_node); (result, dep_node) } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2288d36df17..6c23589b39a 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -296,9 +296,12 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<EarlyBinder<Ty<' } /// Check if a function is async. -fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::IsAsync { +fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Asyncness { let node = tcx.hir().get_by_def_id(def_id); - node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness) + node.fn_sig().map_or(ty::Asyncness::No, |sig| match sig.header.asyncness { + hir::IsAsync::Async(_) => ty::Asyncness::Yes, + hir::IsAsync::NotAsync => ty::Asyncness::No, + }) } fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet<u32> { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index b5458e667ed..8b04bafcda5 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -195,6 +195,7 @@ // // Language features: // tidy-alphabetical-start +#![cfg_attr(not(bootstrap), feature(effects))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index 21c23dabfc2..34dfa9e4c51 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -202,7 +202,7 @@ /// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] -#[const_trait] +// FIXME(effects) #[const_trait] pub trait Drop { /// Executes the destructor for this type. /// diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index 67c8245f0bf..20f0bba4c13 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -72,7 +72,7 @@ use crate::marker::Tuple; )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -#[const_trait] +// FIXME(effects) #[const_trait] pub trait Fn<Args: Tuple>: FnMut<Args> { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -159,7 +159,7 @@ pub trait Fn<Args: Tuple>: FnMut<Args> { )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -#[const_trait] +// FIXME(effects) #[const_trait] pub trait FnMut<Args: Tuple>: FnOnce<Args> { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -238,7 +238,7 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> { )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -#[const_trait] +// FIXME(effects) #[const_trait] pub trait FnOnce<Args: Tuple> { /// The returned type after the call operator is used. #[lang = "fn_once_output"] diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 281f8c1e166..e6cdffd96af 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -234,7 +234,8 @@ fn panic_in_cleanup() -> ! { #[rustc_const_unstable(feature = "core_panic", issue = "none")] pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { - panic_str(msg); + // The panic_display function is hooked by const eval. + panic_display(&msg); } else { // SAFETY: This is only evaluated at compile time, which reliably // handles this UB (in case this branch turns out to be reachable diff --git a/library/std/build.rs b/library/std/build.rs index a81c45609ea..e5509504b84 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -38,6 +38,7 @@ fn main() { || target.contains("vita") || target.contains("nto") || target.contains("xous") + || target.contains("hurd") // See src/bootstrap/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() { diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index eca64fb6063..7582c7444f0 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -5,7 +5,7 @@ //! the [`Read`] and [`Write`] traits, which provide the //! most general interface for reading and writing input and output. //! -//! # Read and Write +//! ## Read and Write //! //! Because they are traits, [`Read`] and [`Write`] are implemented by a number //! of other types, and you can implement them for your types too. As such, @@ -238,6 +238,47 @@ //! contract. The implementation of many of these functions are subject to change over //! time and may call fewer or more syscalls/library functions. //! +//! ## I/O Safety +//! +//! Rust follows an I/O safety discipline that is comparable to its memory safety discipline. This +//! means that file descriptors can be *exclusively owned*. (Here, "file descriptor" is meant to +//! subsume similar concepts that exist across a wide range of operating systems even if they might +//! use a different name, such as "handle".) An exclusively owned file descriptor is one that no +//! other code is allowed to access in any way, but the owner is allowed to access and even close +//! it any time. A type that owns its file descriptor should usually close it in its `drop` +//! function. Types like [`File`] own their file descriptor. Similarly, file descriptors +//! can be *borrowed*, granting the temporary right to perform operations on this file descriptor. +//! This indicates that the file descriptor will not be closed for the lifetime of the borrow, but +//! it does *not* imply any right to close this file descriptor, since it will likely be owned by +//! someone else. +//! +//! The platform-specific parts of the Rust standard library expose types that reflect these +//! concepts, see [`os::unix`] and [`os::windows`]. +//! +//! To uphold I/O safety, it is crucial that no code acts on file descriptors it does not own or +//! borrow, and no code closes file descriptors it does not own. In other words, a safe function +//! that takes a regular integer, treats it as a file descriptor, and acts on it, is *unsound*. +//! +//! Not upholding I/O safety and acting on a file descriptor without proof of ownership can lead to +//! misbehavior and even Undefined Behavior in code that relies on ownership of its file +//! descriptors: a closed file descriptor could be re-allocated, so the original owner of that file +//! descriptor is now working on the wrong file. Some code might even rely on fully encapsulating +//! its file descriptors with no operations being performed by any other part of the program. +//! +//! Note that exclusive ownership of a file descriptor does *not* imply exclusive ownership of the +//! underlying kernel object that the file descriptor references (also called "file description" on +//! some operating systems). File descriptors basically work like [`Arc`]: when you receive an owned +//! file descriptor, you cannot know whether there are any other file descriptors that reference the +//! same kernel object. However, when you create a new kernel object, you know that you are holding +//! the only reference to it. Just be careful not to lend it to anyone, since they can obtain a +//! clone and then you can no longer know what the reference count is! In that sense, [`OwnedFd`] is +//! like `Arc` and [`BorrowedFd<'a>`] is like `&'a Arc` (and similar for the Windows types). In +//! particular, given a `BorrowedFd<'a>`, you are not allowed to close the file descriptor -- just +//! like how, given a `&'a Arc`, you are not allowed to decrement the reference count and +//! potentially free the underlying object. There is no equivalent to `Box` for file descriptors in +//! the standard library (that would be a type that guarantees that the reference count is `1`), +//! however, it would be possible for a crate to define a type with those semantics. +//! //! [`File`]: crate::fs::File //! [`TcpStream`]: crate::net::TcpStream //! [`io::stdout`]: stdout @@ -245,6 +286,11 @@ //! [`?` operator]: ../../book/appendix-02-operators.html //! [`Result`]: crate::result::Result //! [`.unwrap()`]: crate::result::Result::unwrap +//! [`os::unix`]: ../os/unix/io/index.html +//! [`os::windows`]: ../os/windows/io/index.html +//! [`OwnedFd`]: ../os/fd/struct.OwnedFd.html +//! [`BorrowedFd<'a>`]: ../os/fd/struct.BorrowedFd.html +//! [`Arc`]: crate::sync::Arc #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 2180d2974d5..81106d6c62c 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -15,8 +15,9 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed file descriptor. /// -/// This has a lifetime parameter to tie it to the lifetime of something that -/// owns the file descriptor. +/// This has a lifetime parameter to tie it to the lifetime of something that owns the file +/// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file +/// descriptor. /// /// This uses `repr(transparent)` and has the representation of a host file /// descriptor, so it can be used in FFI in places where a file descriptor is @@ -42,7 +43,8 @@ pub struct BorrowedFd<'fd> { /// An owned file descriptor. /// -/// This closes the file descriptor on drop. +/// This closes the file descriptor on drop. It is guaranteed that nobody else will close the file +/// descriptor. /// /// This uses `repr(transparent)` and has the representation of a host file /// descriptor, so it can be used in FFI in places where a file descriptor is @@ -155,7 +157,9 @@ impl FromRawFd for OwnedFd { /// # Safety /// /// The resource pointed to by `fd` must be open and suitable for assuming - /// ownership. The resource must not require any cleanup other than `close`. + /// [ownership][io-safety]. The resource must not require any cleanup other than `close`. + /// + /// [io-safety]: io#io-safety #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { assert_ne!(fd, u32::MAX as RawFd); diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 592e072ad90..ef896ea95c9 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -84,7 +84,10 @@ pub trait FromRawFd { /// /// # Safety /// - /// The `fd` passed in must be a valid and open file descriptor. + /// The `fd` passed in must be an [owned file descriptor][io-safety]; + /// in particular, it must be open. + /// + /// [io-safety]: io#io-safety /// /// # Example /// diff --git a/library/std/src/os/fortanix_sgx/io.rs b/library/std/src/os/fortanix_sgx/io.rs index 7223ade6815..7e57435b65c 100644 --- a/library/std/src/os/fortanix_sgx/io.rs +++ b/library/std/src/os/fortanix_sgx/io.rs @@ -31,15 +31,22 @@ pub trait FromRawFd { /// Constructs a new instance of `Self` from the given raw file /// descriptor and metadata. /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. + /// This function is typically used to **consume ownership** of the + /// specified file descriptor. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. + /// However, consuming ownership is not strictly required. Use a + /// [`From<OwnedFd>::from`] implementation for an API which strictly + /// consumes ownership. + /// + /// # Safety + /// + /// The `fd` passed in must be an [owned file descriptor][io-safety]; + /// in particular, it must be open. + // FIXME: say something about `metadata`. + /// + /// [io-safety]: io#io-safety #[unstable(feature = "sgx_platform", issue = "56975")] unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self; } diff --git a/library/std/src/os/hurd/fs.rs b/library/std/src/os/hurd/fs.rs new file mode 100644 index 00000000000..00ff1560f31 --- /dev/null +++ b/library/std/src/os/hurd/fs.rs @@ -0,0 +1,348 @@ +//! Hurd-specific extensions to primitives in the [`std::fs`] module. +//! +//! [`std::fs`]: crate::fs + +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::Metadata; +use crate::sys_common::AsInner; + +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: crate::fs::Metadata +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + /// Returns the device ID on which this file resides. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_dev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + /// Returns the inode number. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ino()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + /// Returns the file type and mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mode()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + /// Returns the number of hard links to file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_nlink()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + /// Returns the user ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_uid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + /// Returns the group ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_gid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + /// Returns the device ID that this file represents. Only relevant for special file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_rdev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. + /// + /// The size of a symbolic link is the length of the pathname it contains, + /// without a terminating null byte. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_size()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + /// Returns the last access time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + /// Returns the last access time of the file, in nanoseconds since [`st_atime`]. + /// + /// [`st_atime`]: Self::st_atime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + /// Returns the last modification time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`]. + /// + /// [`st_mtime`]: Self::st_mtime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + /// Returns the last status change time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`]. + /// + /// [`st_ctime`]: Self::st_ctime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + /// Returns the "preferred" block size for efficient filesystem I/O. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blksize()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + /// Returns the number of blocks allocated to the file, 512-byte units. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blocks()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_fsid as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_sec as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_sec as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_sec as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/library/std/src/os/hurd/mod.rs b/library/std/src/os/hurd/mod.rs new file mode 100644 index 00000000000..aee86c7f616 --- /dev/null +++ b/library/std/src/os/hurd/mod.rs @@ -0,0 +1,6 @@ +//! Hurd-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod fs; +pub mod raw; diff --git a/library/std/src/os/hurd/raw.rs b/library/std/src/os/hurd/raw.rs new file mode 100644 index 00000000000..fa266663528 --- /dev/null +++ b/library/std/src/os/hurd/raw.rs @@ -0,0 +1,33 @@ +//! Hurd-specific raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#![allow(deprecated)] + +use crate::os::raw::{c_long, c_uint, c_ulong}; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blkcnt_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blksize_t = c_long; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = c_ulong; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type ino_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = c_uint; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type nlink_t = c_ulong; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type off_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type time_t = c_long; + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = c_long; diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index de6d784c65b..24d16e64c86 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -117,6 +117,8 @@ pub mod haiku; pub mod hermit; #[cfg(target_os = "horizon")] pub mod horizon; +#[cfg(target_os = "hurd")] +pub mod hurd; #[cfg(target_os = "illumos")] pub mod illumos; #[cfg(target_os = "ios")] diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs index 33cc5a015b5..f82034663d4 100644 --- a/library/std/src/os/solid/io.rs +++ b/library/std/src/os/solid/io.rs @@ -27,15 +27,21 @@ pub trait FromRawFd { /// Constructs a new instance of `Self` from the given raw file /// descriptor. /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. + /// This function is typically used to **consume ownership** of the + /// specified file descriptor. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. + /// However, consuming ownership is not strictly required. Use a + /// [`From<OwnedFd>::from`] implementation for an API which strictly + /// consumes ownership. + /// + /// # Safety + /// + /// The `fd` passed in must be an [owned file descriptor][io-safety]; + /// in particular, it must be open. + /// + /// [io-safety]: io#io-safety unsafe fn from_raw_fd(fd: RawFd) -> Self; } diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 25b5dbff14f..c12d89ed637 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -6,7 +6,7 @@ //! //! This module provides three types for representing file descriptors, //! with different ownership properties: raw, borrowed, and owned, which are -//! analogous to types used for representing pointers: +//! analogous to types used for representing pointers. These types reflect the Unix version of [I/O safety]. //! //! | Type | Analogous to | //! | ------------------ | ------------ | @@ -65,15 +65,16 @@ //! to be opened and read from or written must be `unsafe`. Rust's safety guarantees //! only cover what the program itself can do, and not what entities outside //! the program can do to it. `/proc/self/mem` is considered to be such an -//! external entity, along with debugging interfaces, and people with physical access to -//! the hardware. This is true even in cases where the program is controlling -//! the external entity. +//! external entity, along with `/proc/self/fd/*`, debugging interfaces, and people with physical +//! access to the hardware. This is true even in cases where the program is controlling the external +//! entity. //! //! If you desire to comprehensively prevent programs from reaching out and //! causing external entities to reach back in and violate memory safety, it's //! necessary to use *sandboxing*, which is outside the scope of `std`. //! //! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd +//! [I/O safety]: crate::io#io-safety #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index 401ec1e7a01..3724e90afbd 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -53,6 +53,8 @@ mod platform { pub use crate::os::haiku::*; #[cfg(target_os = "horizon")] pub use crate::os::horizon::*; + #[cfg(target_os = "hurd")] + pub use crate::os::hurd::*; #[cfg(target_os = "illumos")] pub use crate::os::illumos::*; #[cfg(target_os = "ios")] diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs index e2a401fb696..3d4bb96d458 100644 --- a/library/std/src/os/windows/io/mod.rs +++ b/library/std/src/os/windows/io/mod.rs @@ -6,7 +6,7 @@ //! //! This module provides three types for representing raw handles and sockets //! with different ownership properties: raw, borrowed, and owned, which are -//! analogous to types used for representing pointers: +//! analogous to types used for representing pointers. These types reflect the Windows version of [I/O safety]. //! //! | Type | Analogous to | //! | ---------------------- | ------------ | @@ -47,6 +47,7 @@ //! //! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle //! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket +//! [I/O safety]: crate::io#io-safety #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index 1759e2e7f3f..770583a9ce3 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -62,7 +62,7 @@ pub trait FromRawHandle { /// # Safety /// /// The `handle` passed in must: - /// - be a valid an open handle, + /// - be an [owned handle][io-safety]; in particular, it must be open. /// - be a handle for a resource that may be freed via [`CloseHandle`] /// (as opposed to `RegCloseKey` or other close functions). /// @@ -71,6 +71,7 @@ pub trait FromRawHandle { /// /// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 + /// [io-safety]: io#io-safety #[stable(feature = "from_raw_os", since = "1.1.0")] unsafe fn from_raw_handle(handle: RawHandle) -> Self; } @@ -207,10 +208,11 @@ pub trait FromRawSocket { /// # Safety /// /// The `socket` passed in must: - /// - be a valid an open socket, + /// - be an [owned socket][io-safety]; in particular, it must be open. /// - be a socket that may be freed via [`closesocket`]. /// /// [`closesocket`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket + /// [io-safety]: io#io-safety #[stable(feature = "from_raw_os", since = "1.1.0")] unsafe fn from_raw_socket(sock: RawSocket) -> Self; } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 5df1105e264..948862c2a7d 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -789,7 +789,7 @@ impl Command { /// or [`Command::envs`]. In addition, it will prevent the spawned child process from inheriting /// any environment variable from its parent process. /// - /// After calling [`Command::env_remove`], the iterator from [`Command::get_envs`] will be + /// After calling [`Command::env_clear`], the iterator from [`Command::get_envs`] will be /// empty. /// /// You can use [`Command::env_remove`] to clear a single mapping. diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 00636237288..07d4de5c1a2 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -537,7 +537,7 @@ fn env_empty() { #[test] #[cfg(not(windows))] #[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] -fn main() { +fn debug_print() { const PIDFD: &'static str = if cfg!(target_os = "linux") { " create_pidfd: false,\n" } else { "" }; @@ -626,6 +626,51 @@ fn main() { {PIDFD}}}"# ) ); + + let mut command_with_removed_env = Command::new("boring-name"); + command_with_removed_env.env_remove("FOO").env_remove("BAR"); + assert_eq!(format!("{command_with_removed_env:?}"), r#"env -u BAR -u FOO "boring-name""#); + assert_eq!( + format!("{command_with_removed_env:#?}"), + format!( + r#"Command {{ + program: "boring-name", + args: [ + "boring-name", + ], + env: CommandEnv {{ + clear: false, + vars: {{ + "BAR": None, + "FOO": None, + }}, + }}, +{PIDFD}}}"# + ) + ); + + let mut command_with_cleared_env = Command::new("boring-name"); + command_with_cleared_env.env_clear().env("BAR", "val").env_remove("FOO"); + assert_eq!(format!("{command_with_cleared_env:?}"), r#"env -i BAR="val" "boring-name""#); + assert_eq!( + format!("{command_with_cleared_env:#?}"), + format!( + r#"Command {{ + program: "boring-name", + args: [ + "boring-name", + ], + env: CommandEnv {{ + clear: true, + vars: {{ + "BAR": Some( + "val", + ), + }}, + }}, +{PIDFD}}}"# + ) + ); } // See issue #91991 diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index eafd6821f54..19334e2aff2 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -71,6 +71,7 @@ impl DoubleEndedIterator for Args { target_os = "vxworks", target_os = "horizon", target_os = "nto", + target_os = "hurd", ))] mod imp { use super::Args; diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs index 929e9dae738..c6d8578a629 100644 --- a/library/std/src/sys/unix/env.rs +++ b/library/std/src/sys/unix/env.rs @@ -152,6 +152,17 @@ pub mod os { pub const EXE_EXTENSION: &str = "elf"; } +#[cfg(target_os = "hurd")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "hurd"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "vita")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 85e020ae413..6c4f408426a 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -13,14 +13,16 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; target_os = "android", target_os = "linux", target_os = "emscripten", - target_os = "l4re" + target_os = "l4re", + target_os = "hurd", ))] use libc::off64_t; #[cfg(not(any( target_os = "linux", target_os = "emscripten", target_os = "l4re", - target_os = "android" + target_os = "android", + target_os = "hurd", )))] use libc::off_t as off64_t; @@ -124,9 +126,9 @@ impl FileDesc { } pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - #[cfg(not(any(target_os = "linux", target_os = "android")))] + #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "hurd")))] use libc::pread as pread64; - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "android", target_os = "hurd"))] use libc::pread64; unsafe { @@ -160,6 +162,7 @@ impl FileDesc { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -181,6 +184,7 @@ impl FileDesc { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "ios", target_os = "tvos", @@ -281,9 +285,9 @@ impl FileDesc { } pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { - #[cfg(not(any(target_os = "linux", target_os = "android")))] + #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "hurd")))] use libc::pwrite as pwrite64; - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "android", target_os = "hurd"))] use libc::pwrite64; unsafe { @@ -301,6 +305,7 @@ impl FileDesc { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -322,6 +327,7 @@ impl FileDesc { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "ios", target_os = "tvos", diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 61ea87a5b0c..764e1f25790 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -39,9 +39,14 @@ use libc::{c_int, mode_t}; all(target_os = "linux", target_env = "gnu") ))] use libc::c_char; -#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] +#[cfg(any( + target_os = "linux", + target_os = "emscripten", + target_os = "android", + target_os = "hurd", +))] use libc::dirfd; -#[cfg(any(target_os = "linux", target_os = "emscripten"))] +#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd"))] use libc::fstatat64; #[cfg(any( target_os = "android", @@ -53,7 +58,7 @@ use libc::fstatat64; target_os = "vita", ))] use libc::readdir as readdir64; -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "hurd"))] use libc::readdir64; #[cfg(any(target_os = "emscripten", target_os = "l4re"))] use libc::readdir64_r; @@ -68,6 +73,7 @@ use libc::readdir64_r; target_os = "redox", target_os = "nto", target_os = "vita", + target_os = "hurd", )))] use libc::readdir_r as readdir64_r; #[cfg(target_os = "android")] @@ -79,13 +85,19 @@ use libc::{ target_os = "linux", target_os = "emscripten", target_os = "l4re", - target_os = "android" + target_os = "android", + target_os = "hurd", )))] use libc::{ dirent as dirent64, fstat as fstat64, ftruncate as ftruncate64, lseek as lseek64, lstat as lstat64, off_t as off64_t, open as open64, stat as stat64, }; -#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] +#[cfg(any( + target_os = "linux", + target_os = "emscripten", + target_os = "l4re", + target_os = "hurd" +))] use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64}; pub use crate::sys_common::fs::try_exists; @@ -277,7 +289,8 @@ unsafe impl Sync for Dir {} target_os = "fuchsia", target_os = "redox", target_os = "nto", - target_os = "vita" + target_os = "vita", + target_os = "hurd", ))] pub struct DirEntry { dir: Arc<InnerReadDir>, @@ -300,6 +313,7 @@ pub struct DirEntry { target_os = "redox", target_os = "nto", target_os = "vita", + target_os = "hurd", ))] struct dirent64_min { d_ino: u64, @@ -321,6 +335,7 @@ struct dirent64_min { target_os = "redox", target_os = "nto", target_os = "vita", + target_os = "hurd", )))] pub struct DirEntry { dir: Arc<InnerReadDir>, @@ -455,7 +470,8 @@ impl FileAttr { target_os = "vxworks", target_os = "espidf", target_os = "horizon", - target_os = "vita" + target_os = "vita", + target_os = "hurd", )))] pub fn modified(&self) -> io::Result<SystemTime> { #[cfg(target_pointer_width = "32")] @@ -473,7 +489,7 @@ impl FileAttr { Ok(SystemTime::new(self.stat.st_mtime as i64, 0)) } - #[cfg(target_os = "horizon")] + #[cfg(any(target_os = "horizon", target_os = "hurd"))] pub fn modified(&self) -> io::Result<SystemTime> { Ok(SystemTime::from(self.stat.st_mtim)) } @@ -482,7 +498,8 @@ impl FileAttr { target_os = "vxworks", target_os = "espidf", target_os = "horizon", - target_os = "vita" + target_os = "vita", + target_os = "hurd", )))] pub fn accessed(&self) -> io::Result<SystemTime> { #[cfg(target_pointer_width = "32")] @@ -500,7 +517,7 @@ impl FileAttr { Ok(SystemTime::new(self.stat.st_atime as i64, 0)) } - #[cfg(target_os = "horizon")] + #[cfg(any(target_os = "horizon", target_os = "hurd"))] pub fn accessed(&self) -> io::Result<SystemTime> { Ok(SystemTime::from(self.stat.st_atim)) } @@ -656,6 +673,7 @@ impl Iterator for ReadDir { target_os = "illumos", target_os = "nto", target_os = "vita", + target_os = "hurd", ))] fn next(&mut self) -> Option<io::Result<DirEntry>> { if self.end_of_stream { @@ -756,6 +774,7 @@ impl Iterator for ReadDir { target_os = "illumos", target_os = "nto", target_os = "vita", + target_os = "hurd", )))] fn next(&mut self) -> Option<io::Result<DirEntry>> { if self.end_of_stream { @@ -809,7 +828,12 @@ impl DirEntry { } #[cfg(all( - any(target_os = "linux", target_os = "emscripten", target_os = "android"), + any( + target_os = "linux", + target_os = "emscripten", + target_os = "android", + target_os = "hurd", + ), not(miri) ))] pub fn metadata(&self) -> io::Result<FileAttr> { @@ -833,7 +857,12 @@ impl DirEntry { } #[cfg(any( - not(any(target_os = "linux", target_os = "emscripten", target_os = "android")), + not(any( + target_os = "linux", + target_os = "emscripten", + target_os = "android", + target_os = "hurd", + )), miri ))] pub fn metadata(&self) -> io::Result<FileAttr> { @@ -892,6 +921,7 @@ impl DirEntry { target_os = "horizon", target_os = "vita", target_os = "nto", + target_os = "hurd", ))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 @@ -949,6 +979,7 @@ impl DirEntry { target_os = "redox", target_os = "nto", target_os = "vita", + target_os = "hurd", )))] fn name_cstr(&self) -> &CStr { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } @@ -962,6 +993,7 @@ impl DirEntry { target_os = "redox", target_os = "nto", target_os = "vita", + target_os = "hurd", ))] fn name_cstr(&self) -> &CStr { &self.name @@ -1131,6 +1163,7 @@ impl File { target_os = "netbsd", target_os = "openbsd", target_os = "nto", + target_os = "hurd", ))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) @@ -1146,6 +1179,7 @@ impl File { target_os = "openbsd", target_os = "watchos", target_os = "nto", + target_os = "hurd", )))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) @@ -1456,6 +1490,7 @@ impl fmt::Debug for File { target_os = "linux", target_os = "macos", target_os = "freebsd", + target_os = "hurd", target_os = "netbsd", target_os = "openbsd", target_os = "vxworks" @@ -1477,6 +1512,7 @@ impl fmt::Debug for File { target_os = "linux", target_os = "macos", target_os = "freebsd", + target_os = "hurd", target_os = "netbsd", target_os = "openbsd", target_os = "vxworks" diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 4d17a1b0002..18acd5ecccd 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -59,9 +59,9 @@ use crate::ptr; use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use crate::sys::cvt; use crate::sys::weak::syscall; -#[cfg(not(all(target_os = "linux", target_env = "gnu")))] +#[cfg(not(any(all(target_os = "linux", target_env = "gnu"), target_os = "hurd")))] use libc::sendfile as sendfile64; -#[cfg(all(target_os = "linux", target_env = "gnu"))] +#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_os = "hurd"))] use libc::sendfile64; use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV}; diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 692d3ab7cc9..3edafde71e9 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -204,6 +204,10 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { } if let Some(handler) = handler { rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR); + #[cfg(target_os = "hurd")] + { + rtassert!(signal(libc::SIGLOST, handler) != libc::SIG_ERR); + } } } } diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 48f163b6db0..f450d708dae 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -75,6 +75,7 @@ impl Socket { target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", + target_os = "hurd", target_os = "linux", target_os = "netbsd", target_os = "openbsd", @@ -114,6 +115,7 @@ impl Socket { target_os = "freebsd", target_os = "illumos", target_os = "linux", + target_os = "hurd", target_os = "netbsd", target_os = "openbsd", target_os = "nto", @@ -220,6 +222,7 @@ impl Socket { target_os = "freebsd", target_os = "illumos", target_os = "linux", + target_os = "hurd", target_os = "netbsd", target_os = "openbsd", ))] { diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 57e1a36dace..01ff375d215 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -46,7 +46,8 @@ extern "C" { target_os = "linux", target_os = "emscripten", target_os = "fuchsia", - target_os = "l4re" + target_os = "l4re", + target_os = "hurd", ), link_name = "__errno_location" )] @@ -121,7 +122,10 @@ pub fn set_errno(e: i32) { pub fn error_string(errno: i32) -> String { extern "C" { #[cfg_attr( - all(any(target_os = "linux", target_env = "newlib"), not(target_env = "ohos")), + all( + any(target_os = "linux", target_os = "hurd", target_env = "newlib"), + not(target_env = "ohos") + ), link_name = "__xpg_strerror_r" )] fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int; @@ -359,7 +363,12 @@ pub fn current_exe() -> io::Result<PathBuf> { } } -#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))] +#[cfg(any( + target_os = "linux", + target_os = "hurd", + target_os = "android", + target_os = "emscripten" +))] pub fn current_exe() -> io::Result<PathBuf> { match crate::fs::read_link("/proc/self/exe") { Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!( diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index 938a46bfdd8..1239c65a483 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -21,6 +21,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", + target_os = "hurd", target_os = "linux", target_os = "netbsd", target_os = "openbsd", diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index f729da44774..1ca11a7f9d7 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -586,6 +586,23 @@ impl fmt::Debug for Command { if let Some(ref cwd) = self.cwd { write!(f, "cd {cwd:?} && ")?; } + if self.env.does_clear() { + write!(f, "env -i ")?; + // Altered env vars will be printed next, that should exactly work as expected. + } else { + // Removed env vars need the command to be wrapped in `env`. + let mut any_removed = false; + for (key, value_opt) in self.get_envs() { + if value_opt.is_none() { + if !any_removed { + write!(f, "env ")?; + any_removed = true; + } + write!(f, "-u {} ", key.to_string_lossy())?; + } + } + } + // Altered env vars can just be added in front of the program. for (key, value_opt) in self.get_envs() { if let Some(value) = value_opt { write!(f, "{}={value:?} ", key.to_string_lossy())?; diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 75b54064501..564f8c48290 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -374,6 +374,13 @@ impl Command { return Err(io::Error::last_os_error()); } } + #[cfg(target_os = "hurd")] + { + let ret = sys::signal(libc::SIGLOST, libc::SIG_DFL); + if ret == libc::SIG_ERR { + return Err(io::Error::last_os_error()); + } + } } } @@ -620,6 +627,10 @@ impl Command { let mut default_set = MaybeUninit::<libc::sigset_t>::uninit(); cvt(sigemptyset(default_set.as_mut_ptr()))?; cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGPIPE))?; + #[cfg(target_os = "hurd")] + { + cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGLOST))?; + } cvt_nz(libc::posix_spawnattr_setsigdefault( attrs.0.as_mut_ptr(), default_set.as_ptr(), @@ -993,6 +1004,8 @@ fn signal_string(signal: i32) -> &'static str { target_os = "dragonfly" ))] libc::SIGINFO => " (SIGINFO)", + #[cfg(target_os = "hurd")] + libc::SIGLOST => " (SIGLOST)", _ => "", } } diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs index b59d4ba26af..73c530786b2 100644 --- a/library/std/src/sys/unix/stack_overflow.rs +++ b/library/std/src/sys/unix/stack_overflow.rs @@ -32,6 +32,7 @@ impl Drop for Handler { target_os = "macos", target_os = "dragonfly", target_os = "freebsd", + target_os = "hurd", target_os = "solaris", target_os = "illumos", target_os = "netbsd", @@ -193,6 +194,7 @@ mod imp { target_os = "macos", target_os = "dragonfly", target_os = "freebsd", + target_os = "hurd", target_os = "solaris", target_os = "illumos", target_os = "netbsd", diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 2afec897a88..311ed95022f 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -216,7 +216,8 @@ impl Thread { target_os = "l4re", target_os = "emscripten", target_os = "redox", - target_os = "vxworks" + target_os = "vxworks", + target_os = "hurd", ))] pub fn set_name(_name: &CStr) { // Newlib, Emscripten, and VxWorks have no way to set a thread name. @@ -309,6 +310,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> { target_os = "android", target_os = "emscripten", target_os = "fuchsia", + target_os = "hurd", target_os = "ios", target_os = "tvos", target_os = "linux", @@ -316,25 +318,38 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> { target_os = "solaris", target_os = "illumos", ))] { + #[allow(unused_assignments)] + #[allow(unused_mut)] + let mut quota = usize::MAX; + #[cfg(any(target_os = "android", target_os = "linux"))] { - let quota = cgroups::quota().max(1); + quota = cgroups::quota().max(1); let mut set: libc::cpu_set_t = unsafe { mem::zeroed() }; unsafe { if libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) == 0 { let count = libc::CPU_COUNT(&set) as usize; let count = count.min(quota); - // reported to occur on MIPS kernels older than our minimum supported kernel version for those targets - let count = NonZeroUsize::new(count) - .expect("CPU count must be > 0. This may be a bug in sched_getaffinity(); try upgrading the kernel."); - return Ok(count); + + // According to sched_getaffinity's API it should always be non-zero, but + // some old MIPS kernels were buggy and zero-initialized the mask if + // none was explicitly set. + // In that case we use the sysconf fallback. + if let Some(count) = NonZeroUsize::new(count) { + return Ok(count) + } } } } match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { -1 => Err(io::Error::last_os_error()), 0 => Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")), - cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }), + cpus => { + let count = cpus as usize; + // Cover the unusual situation where we were able to get the quota but not the affinity mask + let count = count.min(quota); + Ok(unsafe { NonZeroUsize::new_unchecked(count) }) + } } } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] { use crate::ptr; @@ -692,6 +707,7 @@ mod cgroups { #[cfg(all( not(target_os = "linux"), not(target_os = "freebsd"), + not(target_os = "hurd"), not(target_os = "macos"), not(target_os = "netbsd"), not(target_os = "openbsd"), @@ -712,6 +728,7 @@ pub mod guard { #[cfg(any( target_os = "linux", target_os = "freebsd", + target_os = "hurd", target_os = "macos", target_os = "netbsd", target_os = "openbsd", @@ -768,6 +785,7 @@ pub mod guard { #[cfg(any( target_os = "android", target_os = "freebsd", + target_os = "hurd", target_os = "linux", target_os = "netbsd", target_os = "l4re" @@ -905,6 +923,7 @@ pub mod guard { #[cfg(any( target_os = "android", target_os = "freebsd", + target_os = "hurd", target_os = "linux", target_os = "netbsd", target_os = "l4re" @@ -936,7 +955,7 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0); let stackaddr = stackptr.addr(); - ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd")) { + ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) { Some(stackaddr - guardsize..stackaddr) } else if cfg!(all(target_os = "linux", target_env = "musl")) { Some(stackaddr - guardsize..stackaddr) diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs index 236d2f2ee29..1da41d4b4bf 100644 --- a/library/std/src/sys/unix/thread_local_dtor.rs +++ b/library/std/src/sys/unix/thread_local_dtor.rs @@ -11,7 +11,7 @@ // Note, however, that we run on lots older linuxes, as well as cross // compiling from a newer linux to an older linux, so we also have a // fallback implementation to use as well. -#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))] +#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox", target_os = "hurd"))] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { use crate::mem; use crate::sys_common::thread_local_dtor::register_dtor_fallback; diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 17b4130c202..4fe61b28488 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -35,7 +35,7 @@ pub(in crate::sys::unix) struct Timespec { } impl SystemTime { - #[cfg_attr(target_os = "horizon", allow(unused))] + #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))] pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime { SystemTime { t: Timespec::new(tv_sec, tv_nsec) } } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 2976a9f578e..4f5b17deaa2 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -32,6 +32,7 @@ cfg_if::cfg_if! { cfg_if::cfg_if! { if #[cfg(any( target_os = "linux", target_os = "android", + target_os = "hurd", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "haiku", target_os = "nto"))] { diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs index 18883048dae..4d295cf0f09 100644 --- a/library/std/src/sys_common/process.rs +++ b/library/std/src/sys_common/process.rs @@ -80,6 +80,10 @@ impl CommandEnv { self.vars.clear(); } + pub fn does_clear(&self) -> bool { + self.clear + } + pub fn have_changed_path(&self) -> bool { self.saw_path || self.clear } diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 62e97c65569..df4f286a526 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -148,3 +148,7 @@ extern "C" {} #[cfg(target_os = "nto")] #[link(name = "gcc_s")] extern "C" {} + +#[cfg(target_os = "hurd")] +#[link(name = "gcc_s")] +extern "C" {} diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index a9aa7524e8b..d58f0d54d3a 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -265,7 +265,8 @@ def default_build_triple(verbose): 'FreeBSD': 'unknown-freebsd', 'Haiku': 'unknown-haiku', 'NetBSD': 'unknown-netbsd', - 'OpenBSD': 'unknown-openbsd' + 'OpenBSD': 'unknown-openbsd', + 'GNU': 'unknown-hurd', } # Consider the direct transformation first and then the special cases @@ -336,6 +337,7 @@ def default_build_triple(verbose): 'i386': 'i686', 'i486': 'i686', 'i686': 'i686', + 'i686-AT386': 'i686', 'i786': 'i686', 'loongarch64': 'loongarch64', 'm68k': 'm68k', diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 1e001fae8ab..8b8d4b23795 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -133,7 +133,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[ // #[cfg(bootstrap)] (Some(Mode::Std), "target_vendor", Some(&["unikraft"])), (Some(Mode::Std), "target_env", Some(&["libnx"])), - (Some(Mode::Std), "target_os", Some(&["teeos"])), + // #[cfg(bootstrap)] hurd + (Some(Mode::Std), "target_os", Some(&["teeos", "hurd"])), + (Some(Mode::Rustc), "target_os", Some(&["hurd"])), // #[cfg(bootstrap)] mips32r6, mips64r6 ( Some(Mode::Std), diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 94605e2a217..5c663386446 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -28,6 +28,7 @@ - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) - [\*-android and \*-androideabi](platform-support/android.md) - [\*-linux-ohos](platform-support/openharmony.md) + - [\*-hurd-gnu](platform-support/hurd.md) - [aarch64-unknown-teeos](platform-support/aarch64-unknown-teeos.md) - [\*-esp-espidf](platform-support/esp-idf.md) - [\*-unknown-fuchsia](platform-support/fuchsia.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 70b35526ee5..7c0c56035c0 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -269,6 +269,7 @@ target | std | host | notes `i686-pc-windows-msvc` | * | | 32-bit Windows XP support [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku +[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD `i686-uwp-windows-gnu` | ? | | diff --git a/src/doc/rustc/src/platform-support/hurd.md b/src/doc/rustc/src/platform-support/hurd.md new file mode 100644 index 00000000000..ddf40213ed4 --- /dev/null +++ b/src/doc/rustc/src/platform-support/hurd.md @@ -0,0 +1,35 @@ +# `i686-unknown-hurd-gnu` + +**Tier: 3** + +[GNU/Hurd] is the GNU Hurd is the GNU project's replacement for the Unix kernel. + +## Target maintainers + +- Samuel Thibault, `samuel.thibault@ens-lyon.org`, https://github.com/sthibaul/ + +## Requirements + +The target supports host tools. + +The GNU/Hurd target supports `std` and uses the standard ELF file format. + +## Building the target + +This target can be built by adding `i686-unknown-hurd-gnu` as target in the rustc list. + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will either need to build Rust with the target enabled (see +"Building the target" above), or build your own copy of `core` by using +`build-std` or similar. + +## Testing + +Tests can be run in the same way as a regular binary. + +## Cross-compilation toolchains and C code + +The target supports C code, the GNU toolchain calls the target +`i686-unknown-gnu`. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 190b1b038b6..c4011461885 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -793,6 +793,7 @@ fn clean_ty_generics<'tcx>( } Some(clean_generic_param_def(param, cx)) } + ty::GenericParamDefKind::Const { is_host_effect: true, .. } => None, ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)), }) .collect::<ThinVec<GenericParamDef>>(); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ef7794cc41e..b665f684167 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -31,7 +31,7 @@ use rustc_resolve::rustdoc::{ use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{self, FileName, Loc}; +use rustc_span::{self, FileName, Loc, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; @@ -622,7 +622,7 @@ impl Item { fn build_fn_header( def_id: DefId, tcx: TyCtxt<'_>, - asyncness: hir::IsAsync, + asyncness: ty::Asyncness, ) -> hir::FnHeader { let sig = tcx.fn_sig(def_id).skip_binder(); let constness = @@ -631,6 +631,10 @@ impl Item { } else { hir::Constness::NotConst }; + let asyncness = match asyncness { + ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP), + ty::Asyncness::No => hir::IsAsync::NotAsync, + }; hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness } } let header = match *self.kind { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index e680b451421..8388f722a7f 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -283,7 +283,7 @@ pub(crate) fn print_evaluated_const( (_, &ty::Ref(..)) => None, (mir::ConstValue::Scalar(_), &ty::Adt(_, _)) => None, (mir::ConstValue::Scalar(_), _) => { - let const_ = mir::ConstantKind::from_value(val, ty); + let const_ = mir::Const::from_value(val, ty); Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type)) } _ => None, @@ -319,20 +319,20 @@ fn format_integer_with_underscore_sep(num: &str) -> String { fn print_const_with_custom_print_scalar<'tcx>( tcx: TyCtxt<'tcx>, - ct: mir::ConstantKind<'tcx>, + ct: mir::Const<'tcx>, underscores_and_type: bool, ) -> String { // Use a slightly different format for integer types which always shows the actual value. // For all other types, fallback to the original `pretty_print_const`. match (ct, ct.ty().kind()) { - (mir::ConstantKind::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => { + (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => { if underscores_and_type { format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str()) } else { int.to_string() } } - (mir::ConstantKind::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => { + (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => { let ty = ct.ty(); let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; let data = int.assert_bits(size); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2f611c31a07..170e559e698 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1599,7 +1599,7 @@ impl PrintWithSpace for hir::Unsafety { impl PrintWithSpace for hir::IsAsync { fn print_with_space(&self) -> &str { match self { - hir::IsAsync::Async => "async ", + hir::IsAsync::Async(_) => "async ", hir::IsAsync::NotAsync => "", } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2f88f6dc6e0..fc2acb6eaa3 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -503,13 +503,6 @@ fn opts() -> Vec<RustcOptGroup> { "PATH", ) }), - unstable("disable-per-crate-search", |o| { - o.optflagmulti( - "", - "disable-per-crate-search", - "disables generating the crate selector on the search box", - ) - }), unstable("persist-doctests", |o| { o.optopt( "", diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 96c5c7fc509..3f60e5a7c4d 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { .tcx .const_eval_poly(def_id.to_def_id()) .ok() - .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty)); + .map(|val| rustc_middle::mir::Const::from_value(val, ty)); if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) { if let ty::Adt(adt, _) = ty.kind() { if adt.is_enum() { diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs index 6e13148f2fc..7c0485914b8 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; - miri_to_const(cx, mir::ConstantKind::from_ty_const(min_val_const, cx.tcx))? + miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))? }, }; let rhs_const = match rhs { Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; - miri_to_const(cx, mir::ConstantKind::from_ty_const(max_val_const, cx.tcx))? + miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))? }, }; let lhs_val = lhs_const.int_value(cx, ty)?; diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index 8072aded851..a10aa65e594 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -315,7 +315,7 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id()); let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id); - if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind { + if let hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) = body_owner_kind { let body_span = cx.tcx.hir().span_with_body(body_owner); if let Some(span) = self.const_span && span.contains(body_span) { return; diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index 102845ceed0..80389cbf84b 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -72,7 +72,7 @@ impl Context { let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id()); match cx.tcx.hir().body_owner_kind(body_owner_def_id) { - hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => { + hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const { .. } => { let body_span = cx.tcx.hir().span_with_body(body_owner); if let Some(span) = self.const_span { diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index fc49b58e0a7..f42836611ca 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -10,6 +10,7 @@ use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -84,7 +85,7 @@ fn find_innermost_closure<'tcx>( cx: &LateContext<'tcx>, mut expr: &'tcx hir::Expr<'tcx>, mut steps: usize, -) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, hir::IsAsync)> { +) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, ty::Asyncness)> { let mut data = None; while let hir::ExprKind::Closure(closure) = expr.kind @@ -98,9 +99,9 @@ fn find_innermost_closure<'tcx>( { expr = body.value; data = Some((body.value, closure.fn_decl, if is_async_closure(body) { - hir::IsAsync::Async + ty::Asyncness::Yes } else { - hir::IsAsync::NotAsync + ty::Asyncness::No })); steps -= 1; } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index c88fce22f7f..a136de86240 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -21,7 +21,7 @@ use std::iter; /// A `LitKind`-like enum to fold constant `Expr`s into. #[derive(Debug, Clone)] pub enum Constant<'tcx> { - Adt(rustc_middle::mir::ConstantKind<'tcx>), + Adt(rustc_middle::mir::Const<'tcx>), /// A `String` (e.g., "abc"). Str(String), /// A binary string (e.g., `b"abc"`). @@ -482,7 +482,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .tcx .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None) .ok() - .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?; + .map(|val| rustc_middle::mir::Const::from_value(val, ty))?; let result = miri_to_const(self.lcx, result)?; self.source = ConstantSource::Constant; Some(result) @@ -655,10 +655,10 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } -pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'tcx>) -> Option<Constant<'tcx>> { +pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> { use rustc_middle::mir::ConstValue; match result { - mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { + mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), @@ -671,11 +671,11 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))), _ => None, }, - mir::ConstantKind::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) => { + mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) => { let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?; String::from_utf8(data.to_owned()).ok().map(Constant::Str) } - mir::ConstantKind::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => { + mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => { let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory(); match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), @@ -714,17 +714,17 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t fn field_of_struct<'tcx>( adt_def: ty::AdtDef<'tcx>, lcx: &LateContext<'tcx>, - result: mir::ConstantKind<'tcx>, + result: mir::Const<'tcx>, field: &Ident, -) -> Option<mir::ConstantKind<'tcx>> { - if let mir::ConstantKind::Val(result, ty) = result +) -> Option<mir::Const<'tcx>> { + if let mir::Const::Val(result, ty) = result && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_diagnostics((result, ty)) && let Some(dc_variant) = dc.variant && let Some(variant) = adt_def.variants().get(dc_variant) && let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name) && let Some(&(val, ty)) = dc.fields.get(field_idx) { - Some(mir::ConstantKind::Val(val, ty)) + Some(mir::Const::Val(val, ty)) } else { None diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 4ef3ec19647..be1c46319c2 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -90,14 +90,14 @@ use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr, - ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, + ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; -use rustc_middle::mir::ConstantKind; +use rustc_middle::mir::Const; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -1510,7 +1510,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let bnd_ty = subst.type_at(0) && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) - && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty) + && let min_const_kind = Const::from_value(const_val, bnd_ty) && let Some(min_const) = miri_to_const(cx, min_const_kind) && let Some(start_const) = constant(cx, cx.typeck_results(), start) { @@ -1526,7 +1526,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let bnd_ty = subst.type_at(0) && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) - && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty) + && let max_const_kind = Const::from_value(const_val, bnd_ty) && let Some(max_const) = miri_to_const(cx, max_const_kind) && let Some(end_const) = constant(cx, cx.typeck_results(), end) { @@ -1958,8 +1958,8 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, /// Checks if the given function kind is an async function. pub fn is_async_fn(kind: FnKind<'_>) -> bool { match kind { - FnKind::ItemFn(_, _, header) => header.asyncness == IsAsync::Async, - FnKind::Method(_, sig) => sig.header.asyncness == IsAsync::Async, + FnKind::ItemFn(_, _, header) => header.asyncness .is_async(), + FnKind::Method(_, sig) => sig.header.asyncness.is_async(), FnKind::Closure => false, } } diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index dc7756533ac..4b06b12fb94 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -207,7 +207,8 @@ fn path_segment_certainty( // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE. if cx.tcx.res_generics_def_id(path_segment.res).is_some() { let generics = cx.tcx.generics_of(def_id); - let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && generics.params.is_empty() + let count = generics.params.len() - generics.host_effect_index.is_some() as usize; + let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && count == 0 { Certainty::Certain(None) } else { @@ -299,7 +300,7 @@ fn type_is_inferrable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> b // Check that all type parameters appear in the functions input types. (0..(generics.parent_count + generics.params.len()) as u32).all(|index| { - fn_sig + Some(index as usize) == generics.host_effect_index || fn_sig .inputs() .iter() .any(|input_ty| contains_param(*input_ty.skip_binder(), index)) diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 073b8b6a661..24b9fa0776f 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -516,8 +516,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; // Atomics wrap around on overflow. - let val = this.binary_op(op, &old, rhs)?; - let val = if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val }; + let val = this.wrapping_binary_op(op, &old, rhs)?; + let val = if neg { this.wrapping_unary_op(mir::UnOp::Not, &val)? } else { val }; this.allow_data_races_mut(|this| this.write_immediate(*val, place))?; this.validate_atomic_rmw(place, atomic)?; @@ -561,7 +561,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; - let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; + let lt = this.wrapping_binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; let new_val = if min { if lt { &old } else { &rhs } @@ -605,7 +605,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; // `binary_op` will bail if either of them is not a scalar. - let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; + let eq = this.wrapping_binary_op(mir::BinOp::Eq, &old, expect_old)?; // If the operation would succeed, but is "weak", fail some portion // of the time, based on `success_rate`. let success_rate = 1.0 - this.machine.cmpxchg_weak_failure_rate; diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index b05087134a0..537c767065d 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1013,15 +1013,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn float_to_int_checked<F>( &self, f: F, - dest_ty: Ty<'tcx>, + cast_to: TyAndLayout<'tcx>, round: rustc_apfloat::Round, - ) -> Option<Scalar<Provenance>> + ) -> Option<ImmTy<'tcx, Provenance>> where F: rustc_apfloat::Float + Into<Scalar<Provenance>>, { let this = self.eval_context_ref(); - match dest_ty.kind() { + let val = match cast_to.ty.kind() { // Unsigned ty::Uint(t) => { let size = Integer::from_uint_ty(this, *t).size(); @@ -1033,11 +1033,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) { // Floating point value is NaN (flagged with INVALID_OP) or outside the range // of values of the integer type (flagged with OVERFLOW or UNDERFLOW). - None + return None } else { // Floating point value can be represented by the integer type after rounding. // The INEXACT flag is ignored on purpose to allow rounding. - Some(Scalar::from_uint(res.value, size)) + Scalar::from_uint(res.value, size) } } // Signed @@ -1051,20 +1051,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) { // Floating point value is NaN (flagged with INVALID_OP) or outside the range // of values of the integer type (flagged with OVERFLOW or UNDERFLOW). - None + return None } else { // Floating point value can be represented by the integer type after rounding. // The INEXACT flag is ignored on purpose to allow rounding. - Some(Scalar::from_int(res.value, size)) + Scalar::from_int(res.value, size) } } // Nothing else _ => span_bug!( this.cur_span(), - "attempted float-to-int conversion with non-int output type {dest_ty:?}" + "attempted float-to-int conversion with non-int output type {}", + cast_to.ty, ), - } + }; + Some(ImmTy::from_scalar(val, cast_to)) } /// Returns an integer type that is twice wide as `ty` diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index ce7f47b5b4f..f1c50794ca8 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -998,7 +998,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { bin_op: mir::BinOp, left: &ImmTy<'tcx, Provenance>, right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, (Scalar<Provenance>, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)> { ecx.binary_ptr_op(bin_op, left, right) } diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 368aa2bacdc..27fe7374ea5 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -1,6 +1,6 @@ use log::trace; -use rustc_middle::{mir, ty::Ty}; +use rustc_middle::mir; use rustc_target::abi::Size; use crate::*; @@ -11,7 +11,7 @@ pub trait EvalContextExt<'tcx> { bin_op: mir::BinOp, left: &ImmTy<'tcx, Provenance>, right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, (Scalar<Provenance>, bool, Ty<'tcx>)>; + ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)>; } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { @@ -20,7 +20,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { bin_op: mir::BinOp, left: &ImmTy<'tcx, Provenance>, right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, (Scalar<Provenance>, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)> { use rustc_middle::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); @@ -50,7 +50,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { Ge => left >= right, _ => bug!(), }; - (Scalar::from_bool(res), false, self.tcx.types.bool) + (ImmTy::from_bool(res, *self.tcx), false) } // Some more operations are possible with atomics. @@ -65,12 +65,12 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { right.to_scalar().to_target_usize(self)?, self.machine.layouts.usize, ); - let (result, overflowing, _ty) = + let (result, overflowing) = self.overflowing_binary_op(bin_op, &left, &right)?; // Construct a new pointer with the provenance of `ptr` (the LHS). let result_ptr = - Pointer::new(ptr.provenance, Size::from_bytes(result.to_target_usize(self)?)); - (Scalar::from_maybe_pointer(result_ptr, self), overflowing, left.layout.ty) + Pointer::new(ptr.provenance, Size::from_bytes(result.to_scalar().to_target_usize(self)?)); + (ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, self), left.layout), overflowing) } _ => span_bug!(self.cur_span(), "Invalid operator on pointers: {:?}", bin_op), diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index ef9d0710448..d54145dbdc7 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -89,10 +89,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [left, right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; - let (val, _overflowed, _ty) = - this.overflowing_binary_op(mir::BinOp::Eq, &left, &right)?; + let val = this.wrapping_binary_op(mir::BinOp::Eq, &left, &right)?; // We're type punning a bool as an u8 here. - this.write_scalar(val, dest)?; + this.write_scalar(val.to_scalar(), dest)?; } "const_allocate" => { // For now, for compatibility with the run-time implementation of this, we just return null. @@ -369,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ty::Float(FloatTy::F32) => { let f = val.to_scalar().to_f32()?; this - .float_to_int_checked(f, dest.layout.ty, Round::TowardZero) + .float_to_int_checked(f, dest.layout, Round::TowardZero) .ok_or_else(|| { err_ub_format!( "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`", @@ -380,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ty::Float(FloatTy::F64) => { let f = val.to_scalar().to_f64()?; this - .float_to_int_checked(f, dest.layout.ty, Round::TowardZero) + .float_to_int_checked(f, dest.layout, Round::TowardZero) .ok_or_else(|| { err_ub_format!( "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`", @@ -396,7 +395,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ), }; - this.write_scalar(res, dest)?; + this.write_immediate(*res, dest)?; } // Other diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index 626ead378e7..49ba7e5556e 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -60,7 +60,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let op = this.read_immediate(&this.project_index(&op, i)?)?; let dest = this.project_index(&dest, i)?; let val = match which { - Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar(), + Op::MirOp(mir_op) => this.wrapping_unary_op(mir_op, &op)?.to_scalar(), Op::Abs => { // Works for f32 and f64. let ty::Float(float_ty) = op.layout.ty.kind() else { @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; let val = match which { Op::MirOp(mir_op) => { - let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; + let (val, overflowed) = this.overflowing_binary_op(mir_op, &left, &right)?; if matches!(mir_op, BinOp::Shl | BinOp::Shr) { // Shifts have extra UB as SIMD operations that the MIR binop does not have. // See <https://github.com/rust-lang/rust/issues/91237>. @@ -188,13 +188,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { // Special handling for boolean-returning operations - assert_eq!(ty, this.tcx.types.bool); - let val = val.to_bool().unwrap(); + assert_eq!(val.layout.ty, this.tcx.types.bool); + let val = val.to_scalar().to_bool().unwrap(); bool_to_simd_element(val, dest.layout.size) } else { - assert_ne!(ty, this.tcx.types.bool); - assert_eq!(ty, dest.layout.ty); - val + assert_ne!(val.layout.ty, this.tcx.types.bool); + assert_eq!(val.layout.ty, dest.layout.ty); + val.to_scalar() } } Op::SaturatingOp(mir_op) => { @@ -304,18 +304,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let op = this.read_immediate(&this.project_index(&op, i)?)?; res = match which { Op::MirOp(mir_op) => { - this.binary_op(mir_op, &res, &op)? + this.wrapping_binary_op(mir_op, &res, &op)? } Op::MirOpBool(mir_op) => { let op = imm_from_bool(simd_element_to_bool(op)?); - this.binary_op(mir_op, &res, &op)? + this.wrapping_binary_op(mir_op, &res, &op)? } Op::Max => { if matches!(res.layout.ty.kind(), ty::Float(_)) { ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout) } else { // Just boring integers, so NaNs to worry about - if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? { + if this.wrapping_binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? { res } else { op @@ -327,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout) } else { // Just boring integers, so NaNs to worry about - if this.binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? { + if this.wrapping_binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? { res } else { op @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let mut res = init; for i in 0..op_len { let op = this.read_immediate(&this.project_index(&op, i)?)?; - res = this.binary_op(mir_op, &res, &op)?; + res = this.wrapping_binary_op(mir_op, &res, &op)?; } this.write_immediate(*res, dest)?; } @@ -441,17 +441,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Int-to-(int|float): always safe (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) if safe_cast || unsafe_cast => - this.int_to_int_or_float(&op, dest.layout.ty)?, + this.int_to_int_or_float(&op, dest.layout)?, // Float-to-float: always safe (ty::Float(_), ty::Float(_)) if safe_cast || unsafe_cast => - this.float_to_float_or_int(&op, dest.layout.ty)?, + this.float_to_float_or_int(&op, dest.layout)?, // Float-to-int in safe mode (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast => - this.float_to_float_or_int(&op, dest.layout.ty)?, + this.float_to_float_or_int(&op, dest.layout)?, // Float-to-int in unchecked mode (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if unsafe_cast => { let f = op.to_scalar().to_f32()?; - this.float_to_int_checked(f, dest.layout.ty, Round::TowardZero) + this.float_to_int_checked(f, dest.layout, Round::TowardZero) .ok_or_else(|| { err_ub_format!( "`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`", @@ -462,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if unsafe_cast => { let f = op.to_scalar().to_f64()?; - this.float_to_int_checked(f, dest.layout.ty, Round::TowardZero) + this.float_to_int_checked(f, dest.layout, Round::TowardZero) .ok_or_else(|| { err_ub_format!( "`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`", @@ -473,12 +473,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } // Ptr-to-ptr cast (ty::RawPtr(..), ty::RawPtr(..)) if ptr_cast => - this.ptr_to_ptr(&op, dest.layout.ty)?, + this.ptr_to_ptr(&op, dest.layout)?, // Ptr/Int casts (ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) if expose_cast => - this.pointer_expose_address_cast(&op, dest.layout.ty)?, + this.pointer_expose_address_cast(&op, dest.layout)?, (ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast => - this.pointer_from_exposed_address_cast(&op, dest.layout.ty)?, + this.pointer_from_exposed_address_cast(&op, dest.layout)?, // Error otherwise _ => throw_unsup_format!( @@ -487,7 +487,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { to_ty = dest.layout.ty, ), }; - this.write_immediate(val, &dest)?; + this.write_immediate(*val, &dest)?; } } "shuffle" => { diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index ccc729aae1a..cbdc500be78 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -80,8 +80,8 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>( ) -> InterpResult<'tcx, Scalar<Provenance>> { match which { FloatBinOp::Arith(which) => { - let (res, _overflow, _ty) = this.overflowing_binary_op(which, left, right)?; - Ok(res) + let res = this.wrapping_binary_op(which, left, right)?; + Ok(res.to_scalar()) } FloatBinOp::Cmp(which) => { let left = left.to_scalar().to_float::<F>()?; diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index 30ad088206a..b6b994b45ac 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -173,12 +173,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { _ => unreachable!(), }; - let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { + let res = this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE semantics. - Scalar::from_int(dest.layout.size.signed_int_min(), dest.layout.size) + ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); - this.write_scalar(res, dest)?; + this.write_immediate(*res, dest)?; } // Used to implement the _mm_cvtsi32_ss and _mm_cvtsi64_ss functions. // Converts `right` from i32/i64 to f32. Returns a SIMD vector with @@ -196,8 +196,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let right = this.read_immediate(right)?; let dest0 = this.project_index(&dest, 0)?; - let res0 = this.int_to_int_or_float(&right, dest0.layout.ty)?; - this.write_immediate(res0, &dest0)?; + let res0 = this.int_to_int_or_float(&right, dest0.layout)?; + this.write_immediate(*res0, &dest0)?; for i in 1..dest_len { this.copy_op( diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index b68690a835c..7e10d1d3726 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -56,36 +56,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; // Widen the operands to avoid overflow - let twice_wide_ty = this.get_twice_wide_int_ty(left.layout.ty); - let twice_wide_layout = this.layout_of(twice_wide_ty)?; - let left = this.int_to_int_or_float(&left, twice_wide_ty)?; - let right = this.int_to_int_or_float(&right, twice_wide_ty)?; + let twice_wide = this.layout_of(this.get_twice_wide_int_ty(left.layout.ty))?; + let left = this.int_to_int_or_float(&left, twice_wide)?; + let right = this.int_to_int_or_float(&right, twice_wide)?; // Calculate left + right + 1 - let (added, _overflow, _ty) = this.overflowing_binary_op( + let added = this.wrapping_binary_op( mir::BinOp::Add, - &ImmTy::from_immediate(left, twice_wide_layout), - &ImmTy::from_immediate(right, twice_wide_layout), + &left, + &right, )?; - let (added, _overflow, _ty) = this.overflowing_binary_op( + let added = this.wrapping_binary_op( mir::BinOp::Add, - &ImmTy::from_scalar(added, twice_wide_layout), - &ImmTy::from_uint(1u32, twice_wide_layout), + &added, + &ImmTy::from_uint(1u32, twice_wide), )?; // Calculate (left + right + 1) / 2 - let (divided, _overflow, _ty) = this.overflowing_binary_op( + let divided = this.wrapping_binary_op( mir::BinOp::Div, - &ImmTy::from_scalar(added, twice_wide_layout), - &ImmTy::from_uint(2u32, twice_wide_layout), + &added, + &ImmTy::from_uint(2u32, twice_wide), )?; // Narrow back to the original type let res = this.int_to_int_or_float( - &ImmTy::from_scalar(divided, twice_wide_layout), - dest.layout.ty, + ÷d, + dest.layout, )?; - this.write_immediate(res, &dest)?; + this.write_immediate(*res, &dest)?; } } // Used to implement the _mm_mulhi_epi16 and _mm_mulhi_epu16 functions. @@ -106,30 +105,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; // Widen the operands to avoid overflow - let twice_wide_ty = this.get_twice_wide_int_ty(left.layout.ty); - let twice_wide_layout = this.layout_of(twice_wide_ty)?; - let left = this.int_to_int_or_float(&left, twice_wide_ty)?; - let right = this.int_to_int_or_float(&right, twice_wide_ty)?; + let twice_wide = this.layout_of(this.get_twice_wide_int_ty(left.layout.ty))?; + let left = this.int_to_int_or_float(&left, twice_wide)?; + let right = this.int_to_int_or_float(&right, twice_wide)?; // Multiply - let (multiplied, _overflow, _ty) = this.overflowing_binary_op( + let multiplied = this.wrapping_binary_op( mir::BinOp::Mul, - &ImmTy::from_immediate(left, twice_wide_layout), - &ImmTy::from_immediate(right, twice_wide_layout), + &left, + &right, )?; // Keep the high half - let (high, _overflow, _ty) = this.overflowing_binary_op( + let high = this.wrapping_binary_op( mir::BinOp::Shr, - &ImmTy::from_scalar(multiplied, twice_wide_layout), - &ImmTy::from_uint(dest.layout.size.bits(), twice_wide_layout), + &multiplied, + &ImmTy::from_uint(dest.layout.size.bits(), twice_wide), )?; // Narrow back to the original type let res = this.int_to_int_or_float( - &ImmTy::from_scalar(high, twice_wide_layout), - dest.layout.ty, + &high, + dest.layout, )?; - this.write_immediate(res, &dest)?; + this.write_immediate(*res, &dest)?; } } // Used to implement the _mm_mul_epu32 function. @@ -392,11 +390,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; let res = - this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { + this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE2 semantics. - Scalar::from_i32(i32::MIN) + ImmTy::from_int(i32::MIN, this.machine.layouts.i32) }); - this.write_scalar(res, &dest)?; + this.write_immediate(*res, &dest)?; } } // Used to implement the _mm_packs_epi16 function. @@ -648,8 +646,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let op = this.read_immediate(&this.project_index(&op, i)?)?; let dest = this.project_index(&dest, i)?; - let res = this.float_to_float_or_int(&op, dest.layout.ty)?; - this.write_immediate(res, &dest)?; + let res = this.float_to_float_or_int(&op, dest.layout)?; + this.write_immediate(*res, &dest)?; } // For f32 -> f64, ignore the remaining // For f64 -> f32, fill the remaining with zeros @@ -685,11 +683,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; let res = - this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { + this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE2 semantics. - Scalar::from_i32(i32::MIN) + ImmTy::from_int(i32::MIN, this.machine.layouts.i32) }); - this.write_scalar(res, &dest)?; + this.write_immediate(*res, &dest)?; } // Fill the remaining with zeros for i in op_len..dest_len { @@ -716,12 +714,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { _ => unreachable!(), }; - let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { + let res = this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE semantics. - Scalar::from_int(dest.layout.size.signed_int_min(), dest.layout.size) + ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); - this.write_scalar(res, dest)?; + this.write_immediate(*res, dest)?; } // Used to implement the _mm_cvtsd_ss and _mm_cvtss_sd functions. // Converts the first f64/f32 from `right` to f32/f64 and copies @@ -741,8 +739,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest0 = this.project_index(&dest, 0)?; // `float_to_float_or_int` here will convert from f64 to f32 (cvtsd2ss) or // from f32 to f64 (cvtss2sd). - let res0 = this.float_to_float_or_int(&right0, dest0.layout.ty)?; - this.write_immediate(res0, &dest0)?; + let res0 = this.float_to_float_or_int(&right0, dest0.layout)?; + this.write_immediate(*res0, &dest0)?; // Copy remianing from `left` for i in 1..dest_len { diff --git a/tests/coverage-map/status-quo/loops_branches.cov-map b/tests/coverage-map/status-quo/loops_branches.cov-map index 56fafc0a67b..480bbfd9795 100644 --- a/tests/coverage-map/status-quo/loops_branches.cov-map +++ b/tests/coverage-map/status-quo/loops_branches.cov-map @@ -1,62 +1,58 @@ Function name: <loops_branches::DebugTest as core::fmt::Debug>::fmt -Raw bytes (262): 0x[01, 01, 36, 05, 09, 0a, 02, 00, 00, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, d3, 01, d7, 01, 0d, 00, 11, 15, ca, 01, 00, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, bb, 01, 11, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, 25, b3, 01, b6, 01, 19, bb, 01, 11, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, ca, 01, 03, 0d, 00, 0e, cf, 01, 00, 12, 00, 17, 2b, 01, 10, 00, 14, c6, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, c2, 01, 01, 12, 00, 13, bb, 01, 01, 11, 00, 22, b6, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, af, 01, 01, 05, 00, 06] +Raw bytes (251): 0x[01, 01, 32, 05, 09, 00, 02, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, c3, 01, c7, 01, 0d, 00, 11, 15, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, 00, b2, 01, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, af, 01, 11, 00, b2, 01, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, 25, a7, 01, aa, 01, 19, af, 01, 11, 00, b2, 01, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, ba, 01, 03, 0d, 00, 0e, bf, 01, 00, 12, 00, 17, 27, 01, 10, 00, 14, b6, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b2, 01, 01, 12, 00, 13, af, 01, 01, 11, 00, 22, aa, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, a3, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 54 +Number of expressions: 50 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) -- expression 1 operands: lhs = Expression(2, Sub), rhs = Expression(0, Sub) -- expression 2 operands: lhs = Zero, rhs = Zero -- expression 3 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 4 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 5 operands: lhs = Counter(3), rhs = Zero -- expression 6 operands: lhs = Counter(4), rhs = Counter(5) -- expression 7 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 8 operands: lhs = Counter(3), rhs = Zero -- expression 9 operands: lhs = Counter(4), rhs = Counter(5) -- expression 10 operands: lhs = Expression(50, Sub), rhs = Zero -- expression 11 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 12 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 13 operands: lhs = Counter(3), rhs = Zero -- expression 14 operands: lhs = Counter(4), rhs = Counter(5) -- expression 15 operands: lhs = Expression(50, Sub), rhs = Counter(5) -- expression 16 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 17 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 18 operands: lhs = Counter(3), rhs = Zero -- expression 19 operands: lhs = Counter(4), rhs = Counter(5) -- expression 20 operands: lhs = Expression(49, Sub), rhs = Counter(7) -- expression 21 operands: lhs = Expression(50, Sub), rhs = Counter(5) -- expression 22 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 23 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 24 operands: lhs = Counter(3), rhs = Zero -- expression 25 operands: lhs = Counter(4), rhs = Counter(5) -- expression 26 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub) -- expression 27 operands: lhs = Zero, rhs = Zero -- expression 28 operands: lhs = Expression(49, Sub), rhs = Counter(7) -- expression 29 operands: lhs = Expression(50, Sub), rhs = Counter(5) -- expression 30 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 31 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 32 operands: lhs = Counter(3), rhs = Zero -- expression 33 operands: lhs = Counter(4), rhs = Counter(5) -- expression 34 operands: lhs = Expression(46, Add), rhs = Counter(4) -- expression 35 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub) -- expression 36 operands: lhs = Zero, rhs = Zero -- expression 37 operands: lhs = Expression(49, Sub), rhs = Counter(7) -- expression 38 operands: lhs = Expression(50, Sub), rhs = Counter(5) -- expression 39 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 40 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 41 operands: lhs = Counter(3), rhs = Zero -- expression 42 operands: lhs = Counter(4), rhs = Counter(5) -- expression 43 operands: lhs = Counter(9), rhs = Expression(44, Add) -- expression 44 operands: lhs = Expression(45, Sub), rhs = Counter(6) -- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(4) -- expression 46 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub) -- expression 47 operands: lhs = Zero, rhs = Zero -- expression 48 operands: lhs = Expression(49, Sub), rhs = Counter(7) -- expression 49 operands: lhs = Expression(50, Sub), rhs = Counter(5) -- expression 50 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 51 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 52 operands: lhs = Counter(3), rhs = Zero -- expression 53 operands: lhs = Counter(4), rhs = Counter(5) +- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub) +- expression 2 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 3 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 4 operands: lhs = Counter(3), rhs = Zero +- expression 5 operands: lhs = Counter(4), rhs = Counter(5) +- expression 6 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 7 operands: lhs = Counter(3), rhs = Zero +- expression 8 operands: lhs = Counter(4), rhs = Counter(5) +- expression 9 operands: lhs = Expression(46, Sub), rhs = Zero +- expression 10 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 11 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 12 operands: lhs = Counter(3), rhs = Zero +- expression 13 operands: lhs = Counter(4), rhs = Counter(5) +- expression 14 operands: lhs = Expression(46, Sub), rhs = Counter(5) +- expression 15 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 16 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 17 operands: lhs = Counter(3), rhs = Zero +- expression 18 operands: lhs = Counter(4), rhs = Counter(5) +- expression 19 operands: lhs = Expression(45, Sub), rhs = Counter(7) +- expression 20 operands: lhs = Expression(46, Sub), rhs = Counter(5) +- expression 21 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 22 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 23 operands: lhs = Counter(3), rhs = Zero +- expression 24 operands: lhs = Counter(4), rhs = Counter(5) +- expression 25 operands: lhs = Zero, rhs = Expression(44, Sub) +- expression 26 operands: lhs = Expression(45, Sub), rhs = Counter(7) +- expression 27 operands: lhs = Expression(46, Sub), rhs = Counter(5) +- expression 28 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 29 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 30 operands: lhs = Counter(3), rhs = Zero +- expression 31 operands: lhs = Counter(4), rhs = Counter(5) +- expression 32 operands: lhs = Expression(43, Add), rhs = Counter(4) +- expression 33 operands: lhs = Zero, rhs = Expression(44, Sub) +- expression 34 operands: lhs = Expression(45, Sub), rhs = Counter(7) +- expression 35 operands: lhs = Expression(46, Sub), rhs = Counter(5) +- expression 36 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 37 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 38 operands: lhs = Counter(3), rhs = Zero +- expression 39 operands: lhs = Counter(4), rhs = Counter(5) +- expression 40 operands: lhs = Counter(9), rhs = Expression(41, Add) +- expression 41 operands: lhs = Expression(42, Sub), rhs = Counter(6) +- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(4) +- expression 43 operands: lhs = Zero, rhs = Expression(44, Sub) +- expression 44 operands: lhs = Expression(45, Sub), rhs = Counter(7) +- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(5) +- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 47 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 48 operands: lhs = Counter(3), rhs = Zero +- expression 49 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21) @@ -65,91 +61,87 @@ Number of file 0 mappings: 20 - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 15) = (c1 - c2) - Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 30) - = ((Zero - Zero) + (c1 - c2)) + = (Zero + (c1 - c2)) - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31) - Code(Zero) at (prev + 1, 16) to (start + 1, 10) -- Code(Expression(50, Sub)) at (prev + 3, 13) to (start + 0, 14) +- Code(Expression(46, Sub)) at (prev + 3, 13) to (start + 0, 14) = (((c3 + Zero) + (c4 + c5)) - c6) -- Code(Expression(51, Add)) at (prev + 0, 18) to (start + 0, 23) +- Code(Expression(47, Add)) at (prev + 0, 18) to (start + 0, 23) = ((c3 + Zero) + (c4 + c5)) -- Code(Expression(10, Add)) at (prev + 1, 16) to (start + 0, 20) +- Code(Expression(9, Add)) at (prev + 1, 16) to (start + 0, 20) = ((((c3 + Zero) + (c4 + c5)) - c6) + Zero) -- Code(Expression(49, Sub)) at (prev + 1, 20) to (start + 0, 25) +- Code(Expression(45, Sub)) at (prev + 1, 20) to (start + 0, 25) = ((((c3 + Zero) + (c4 + c5)) - c6) - c5) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(48, Sub)) at (prev + 1, 18) to (start + 0, 19) +- Code(Expression(44, Sub)) at (prev + 1, 18) to (start + 0, 19) = (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7) -- Code(Expression(46, Add)) at (prev + 1, 17) to (start + 0, 34) - = ((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) -- Code(Expression(45, Sub)) at (prev + 0, 34) to (start + 0, 35) - = (((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) +- Code(Expression(43, Add)) at (prev + 1, 17) to (start + 0, 34) + = (Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) +- Code(Expression(42, Sub)) at (prev + 0, 34) to (start + 0, 35) + = ((Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) - Code(Zero) at (prev + 1, 20) to (start + 1, 14) - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) -- Code(Expression(43, Add)) at (prev + 1, 5) to (start + 0, 6) - = (c9 + ((((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) + c6)) +- Code(Expression(40, Add)) at (prev + 1, 5) to (start + 0, 6) + = (c9 + (((Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) + c6)) Function name: <loops_branches::DisplayTest as core::fmt::Display>::fmt -Raw bytes (266): 0x[01, 01, 38, 01, 05, 02, 09, 0e, 12, 00, 00, 02, 09, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, d7, 01, db, 01, 05, 0d, 11, 15, ce, 01, 00, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, bf, 01, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ba, 01, df, 01, bf, 01, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, 19, 25, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 12, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, ce, 01, 02, 0d, 00, 0e, d3, 01, 00, 12, 00, 17, 33, 01, 10, 00, 15, 00, 00, 16, 01, 0e, ca, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, c6, 01, 01, 12, 00, 13, bf, 01, 01, 11, 00, 22, ba, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, b7, 01, 01, 05, 00, 06] +Raw bytes (255): 0x[01, 01, 34, 01, 05, 02, 09, 00, 0e, 02, 09, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, c7, 01, cb, 01, 05, 0d, 11, 15, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, 00, b6, 01, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, b3, 01, 15, 00, b6, 01, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, ae, 01, cf, 01, b3, 01, 15, 00, b6, 01, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, 19, 25, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 0e, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, be, 01, 02, 0d, 00, 0e, c3, 01, 00, 12, 00, 17, 2f, 01, 10, 00, 15, 00, 00, 16, 01, 0e, ba, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b6, 01, 01, 12, 00, 13, b3, 01, 01, 11, 00, 22, ae, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, ab, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 56 +Number of expressions: 52 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Expression(0, Sub), rhs = Counter(2) -- expression 2 operands: lhs = Expression(3, Sub), rhs = Expression(4, Sub) -- expression 3 operands: lhs = Zero, rhs = Zero -- expression 4 operands: lhs = Expression(0, Sub), rhs = Counter(2) -- expression 5 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 6 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 7 operands: lhs = Counter(1), rhs = Counter(3) -- expression 8 operands: lhs = Counter(4), rhs = Counter(5) -- expression 9 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 10 operands: lhs = Counter(1), rhs = Counter(3) -- expression 11 operands: lhs = Counter(4), rhs = Counter(5) -- expression 12 operands: lhs = Expression(51, Sub), rhs = Zero -- expression 13 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 14 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 15 operands: lhs = Counter(1), rhs = Counter(3) -- expression 16 operands: lhs = Counter(4), rhs = Counter(5) -- expression 17 operands: lhs = Expression(51, Sub), rhs = Counter(4) -- expression 18 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 19 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 20 operands: lhs = Counter(1), rhs = Counter(3) -- expression 21 operands: lhs = Counter(4), rhs = Counter(5) -- expression 22 operands: lhs = Expression(50, Sub), rhs = Counter(7) -- expression 23 operands: lhs = Expression(51, Sub), rhs = Counter(4) -- expression 24 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 25 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 26 operands: lhs = Counter(1), rhs = Counter(3) -- expression 27 operands: lhs = Counter(4), rhs = Counter(5) -- expression 28 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub) -- expression 29 operands: lhs = Zero, rhs = Zero -- expression 30 operands: lhs = Expression(50, Sub), rhs = Counter(7) -- expression 31 operands: lhs = Expression(51, Sub), rhs = Counter(4) -- expression 32 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 33 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 34 operands: lhs = Counter(1), rhs = Counter(3) -- expression 35 operands: lhs = Counter(4), rhs = Counter(5) -- expression 36 operands: lhs = Expression(47, Add), rhs = Counter(5) -- expression 37 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub) -- expression 38 operands: lhs = Zero, rhs = Zero -- expression 39 operands: lhs = Expression(50, Sub), rhs = Counter(7) -- expression 40 operands: lhs = Expression(51, Sub), rhs = Counter(4) -- expression 41 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 42 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 43 operands: lhs = Counter(1), rhs = Counter(3) -- expression 44 operands: lhs = Counter(4), rhs = Counter(5) -- expression 45 operands: lhs = Expression(46, Sub), rhs = Expression(55, Add) -- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(5) -- expression 47 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub) -- expression 48 operands: lhs = Zero, rhs = Zero -- expression 49 operands: lhs = Expression(50, Sub), rhs = Counter(7) -- expression 50 operands: lhs = Expression(51, Sub), rhs = Counter(4) -- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 52 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 53 operands: lhs = Counter(1), rhs = Counter(3) -- expression 54 operands: lhs = Counter(4), rhs = Counter(5) -- expression 55 operands: lhs = Counter(6), rhs = Counter(9) +- expression 2 operands: lhs = Zero, rhs = Expression(3, Sub) +- expression 3 operands: lhs = Expression(0, Sub), rhs = Counter(2) +- expression 4 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 5 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 6 operands: lhs = Counter(1), rhs = Counter(3) +- expression 7 operands: lhs = Counter(4), rhs = Counter(5) +- expression 8 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 9 operands: lhs = Counter(1), rhs = Counter(3) +- expression 10 operands: lhs = Counter(4), rhs = Counter(5) +- expression 11 operands: lhs = Expression(47, Sub), rhs = Zero +- expression 12 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 13 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 14 operands: lhs = Counter(1), rhs = Counter(3) +- expression 15 operands: lhs = Counter(4), rhs = Counter(5) +- expression 16 operands: lhs = Expression(47, Sub), rhs = Counter(4) +- expression 17 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 18 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 19 operands: lhs = Counter(1), rhs = Counter(3) +- expression 20 operands: lhs = Counter(4), rhs = Counter(5) +- expression 21 operands: lhs = Expression(46, Sub), rhs = Counter(7) +- expression 22 operands: lhs = Expression(47, Sub), rhs = Counter(4) +- expression 23 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 24 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 25 operands: lhs = Counter(1), rhs = Counter(3) +- expression 26 operands: lhs = Counter(4), rhs = Counter(5) +- expression 27 operands: lhs = Zero, rhs = Expression(45, Sub) +- expression 28 operands: lhs = Expression(46, Sub), rhs = Counter(7) +- expression 29 operands: lhs = Expression(47, Sub), rhs = Counter(4) +- expression 30 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 31 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 32 operands: lhs = Counter(1), rhs = Counter(3) +- expression 33 operands: lhs = Counter(4), rhs = Counter(5) +- expression 34 operands: lhs = Expression(44, Add), rhs = Counter(5) +- expression 35 operands: lhs = Zero, rhs = Expression(45, Sub) +- expression 36 operands: lhs = Expression(46, Sub), rhs = Counter(7) +- expression 37 operands: lhs = Expression(47, Sub), rhs = Counter(4) +- expression 38 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 39 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 40 operands: lhs = Counter(1), rhs = Counter(3) +- expression 41 operands: lhs = Counter(4), rhs = Counter(5) +- expression 42 operands: lhs = Expression(43, Sub), rhs = Expression(51, Add) +- expression 43 operands: lhs = Expression(44, Add), rhs = Counter(5) +- expression 44 operands: lhs = Zero, rhs = Expression(45, Sub) +- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(7) +- expression 46 operands: lhs = Expression(47, Sub), rhs = Counter(4) +- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 48 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 49 operands: lhs = Counter(1), rhs = Counter(3) +- expression 50 operands: lhs = Counter(4), rhs = Counter(5) +- expression 51 operands: lhs = Counter(6), rhs = Counter(9) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17) - Code(Zero) at (prev + 1, 18) to (start + 1, 10) @@ -157,31 +149,31 @@ Number of file 0 mappings: 20 = (c0 - c1) - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) -- Code(Expression(4, Sub)) at (prev + 1, 14) to (start + 0, 15) +- Code(Expression(3, Sub)) at (prev + 1, 14) to (start + 0, 15) = ((c0 - c1) - c2) - Code(Expression(2, Add)) at (prev + 1, 13) to (start + 0, 30) - = ((Zero - Zero) + ((c0 - c1) - c2)) + = (Zero + ((c0 - c1) - c2)) - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31) -- Code(Expression(51, Sub)) at (prev + 2, 13) to (start + 0, 14) +- Code(Expression(47, Sub)) at (prev + 2, 13) to (start + 0, 14) = (((c1 + c3) + (c4 + c5)) - c6) -- Code(Expression(52, Add)) at (prev + 0, 18) to (start + 0, 23) +- Code(Expression(48, Add)) at (prev + 0, 18) to (start + 0, 23) = ((c1 + c3) + (c4 + c5)) -- Code(Expression(12, Add)) at (prev + 1, 16) to (start + 0, 21) +- Code(Expression(11, Add)) at (prev + 1, 16) to (start + 0, 21) = ((((c1 + c3) + (c4 + c5)) - c6) + Zero) - Code(Zero) at (prev + 0, 22) to (start + 1, 14) -- Code(Expression(50, Sub)) at (prev + 2, 20) to (start + 0, 25) +- Code(Expression(46, Sub)) at (prev + 2, 20) to (start + 0, 25) = ((((c1 + c3) + (c4 + c5)) - c6) - c4) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(49, Sub)) at (prev + 1, 18) to (start + 0, 19) +- Code(Expression(45, Sub)) at (prev + 1, 18) to (start + 0, 19) = (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7) -- Code(Expression(47, Add)) at (prev + 1, 17) to (start + 0, 34) - = ((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) -- Code(Expression(46, Sub)) at (prev + 0, 34) to (start + 0, 35) - = (((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) +- Code(Expression(44, Add)) at (prev + 1, 17) to (start + 0, 34) + = (Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) +- Code(Expression(43, Sub)) at (prev + 0, 34) to (start + 0, 35) + = ((Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) -- Code(Expression(45, Add)) at (prev + 1, 5) to (start + 0, 6) - = ((((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) + (c6 + c9)) +- Code(Expression(42, Add)) at (prev + 1, 5) to (start + 0, 6) + = (((Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) + (c6 + c9)) Function name: loops_branches::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02] diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir index 18a663d9f9e..1d3317efd41 100644 --- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir @@ -9,9 +9,9 @@ fn outer(_1: u8) -> u8 { StorageLive(_2); // scope 0 at $DIR/spans.rs:10:11: 10:13 _2 = &_1; // scope 0 at $DIR/spans.rs:10:11: 10:13 _0 = inner(move _2) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/spans.rs:10:5: 10:14 - // mir::Constant + // mir::ConstOperand // + span: $DIR/spans.rs:10:5: 10:10 - // + literal: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) } + // + const_: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) } } bb1: { diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir index 1c02fb72bcd..aba66861f7d 100644 --- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir @@ -9,9 +9,9 @@ fn outer(_1: u8) -> u8 { StorageLive(_2); // scope 0 at $DIR/spans.rs:10:11: 10:13 _2 = &_1; // scope 0 at $DIR/spans.rs:10:11: 10:13 _0 = inner(move _2) -> [return: bb1, unwind continue]; // scope 0 at $DIR/spans.rs:10:5: 10:14 - // mir::Constant + // mir::ConstOperand // + span: $DIR/spans.rs:10:5: 10:10 - // + literal: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) } + // + const_: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) } } bb1: { diff --git a/tests/run-make/issue-88756-default-output/output-default.stdout b/tests/run-make/issue-88756-default-output/output-default.stdout index f5981045b03..38a3965f0c5 100644 --- a/tests/run-make/issue-88756-default-output/output-default.stdout +++ b/tests/run-make/issue-88756-default-output/output-default.stdout @@ -133,9 +133,6 @@ Options: Path string to force loading static files from in output pages. If not set, uses combinations of '../' to reach the documentation root. - --disable-per-crate-search - disables generating the crate selector on the search - box --persist-doctests PATH Directory to persist doctest executables into --show-coverage diff --git a/tests/rustdoc/no-crate-filter.rs b/tests/rustdoc/no-crate-filter.rs deleted file mode 100644 index b2f89906480..00000000000 --- a/tests/rustdoc/no-crate-filter.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![crate_name = "foo"] - -// compile-flags: -Z unstable-options --disable-per-crate-search - -// @!has 'foo/struct.Foo.html' '//*[id="crate-search"]' '' -pub struct Foo; diff --git a/tests/rustdoc/rfc-2632-const-trait-impl.rs b/tests/rustdoc/rfc-2632-const-trait-impl.rs index 5d742dc391a..7f56b2ffeb8 100644 --- a/tests/rustdoc/rfc-2632-const-trait-impl.rs +++ b/tests/rustdoc/rfc-2632-const-trait-impl.rs @@ -5,6 +5,8 @@ // To future blessers: make sure that `const_trait_impl` is // stabilized when changing `@!has` to `@has`, and please do // not remove this test. +// +// FIXME(effects) add `const_trait` to `Fn` so we use `~const` #![feature(const_trait_impl)] #![crate_name = "foo"] @@ -22,9 +24,9 @@ pub trait Tr<T> { // @has - '//section[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Fn' // @!has - '//section[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const' // @has - '//section[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Fn' - fn a<A: ~const Fn() + ~const Destruct>() + fn a<A: /* ~const */ Fn() + ~const Destruct>() where - Option<A>: ~const Fn() + ~const Destruct, + Option<A>: /* ~const */ Fn() + ~const Destruct, { } } @@ -34,13 +36,13 @@ pub trait Tr<T> { // @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/a[@class="trait"]' 'Fn' // @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where"]' '~const' // @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where fmt-newline"]' ': Fn' -impl<T: ~const Fn() + ~const Destruct> const Tr<T> for T +impl<T: /* ~const */ Fn() + ~const Destruct> const Tr<T> for T where - Option<T>: ~const Fn() + ~const Destruct, + Option<T>: /* ~const */ Fn() + ~const Destruct, { - fn a<A: ~const Fn() + ~const Destruct>() + fn a<A: /* ~const */ Fn() + ~const Destruct>() where - Option<A>: ~const Fn() + ~const Destruct, + Option<A>: /* ~const */ Fn() + ~const Destruct, { } } @@ -49,9 +51,9 @@ where // @has - '//pre[@class="rust item-decl"]/code/a[@class="trait"]' 'Fn' // @!has - '//pre[@class="rust item-decl"]/code/span[@class="where fmt-newline"]' '~const' // @has - '//pre[@class="rust item-decl"]/code/span[@class="where fmt-newline"]' ': Fn' -pub const fn foo<F: ~const Fn() + ~const Destruct>() +pub const fn foo<F: /* ~const */ Fn() + ~const Destruct>() where - Option<F>: ~const Fn() + ~const Destruct, + Option<F>: /* ~const */ Fn() + ~const Destruct, { F::a() } @@ -61,9 +63,9 @@ impl<T> S<T> { // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Fn' // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const' // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Fn' - pub const fn foo<B, C: ~const Fn() + ~const Destruct>() + pub const fn foo<B, C: /* ~const */ Fn() + ~const Destruct>() where - B: ~const Fn() + ~const Destruct, + B: /* ~const */ Fn() + ~const Destruct, { B::a() } diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs index 642b58b0753..283d87d3eb6 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs @@ -1,7 +1,7 @@ // check-fail // Tests that a doc comment will not preclude a field from being considered a diagnostic argument // normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr" -// normalize-stderr-test "diagnostic_builder\.rs:[0-9]+:[0-9]+" -> "diagnostic_builder.rs:LL:CC" +// normalize-stderr-test "(COMPILER_DIR/.*\.rs):[0-9]+:[0-9]+" -> "$1:LL:CC" // The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly, // changing the output of this test. Since Subdiagnostic is strictly internal to the compiler diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index e014fc8c693..70d7b3225b5 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -23,7 +23,7 @@ LL | arg: NotIntoDiagnosticArg, | = help: normalized in stderr note: required by a bound in `Diagnostic::set_arg` - --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:968:5 + --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC error: aborting due to 2 previous errors diff --git a/tests/ui/associated-inherent-types/issue-111879-1.stderr b/tests/ui/associated-inherent-types/issue-111879-1.stderr index 689b45e09aa..bf35f2bb5b5 100644 --- a/tests/ui/associated-inherent-types/issue-111879-1.stderr +++ b/tests/ui/associated-inherent-types/issue-111879-1.stderr @@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type LL | fn main(_: for<'a> fn(Foo<fn(&'a ())>::Assoc)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn()` - found fn pointer `fn(for<'a> fn(Foo<fn(&'a ())>::Assoc))` + = note: expected signature `fn()` + found signature `fn(for<'a> fn(&'a ()))` error: aborting due to previous error diff --git a/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs b/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs new file mode 100644 index 00000000000..bba886f175e --- /dev/null +++ b/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs @@ -0,0 +1,7 @@ +// edition:2021 + +#![feature(async_fn_in_trait)] + +pub trait Foo { + async fn test(); +} diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr index 18185b75554..7e59d94d456 100644 --- a/tests/ui/async-await/in-trait/missing-send-bound.stderr +++ b/tests/ui/async-await/in-trait/missing-send-bound.stderr @@ -15,6 +15,11 @@ note: required by a bound in `assert_is_send` | LL | fn assert_is_send(_: impl Send) {} | ^^^^ required by this bound in `assert_is_send` +help: `Send` can be made part of the associated future's guarantees for all implementations of `Foo::bar` + | +LL - async fn bar(); +LL + fn bar() -> impl std::future::Future<Output = ()> + Send; + | error: aborting due to previous error diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed new file mode 100644 index 00000000000..33c00587439 --- /dev/null +++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed @@ -0,0 +1,20 @@ +// run-rustfix +// edition: 2021 + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] +#![allow(unused)] + +trait Foo { + fn test() -> impl std::future::Future<Output = ()> + Send { async {} } + fn test2() -> impl std::future::Future<Output = i32> + Send {async { 1 + 2 } } +} + +fn bar<T: Foo>() { + fn needs_send(_: impl Send) {} + needs_send(T::test()); + //~^ ERROR `impl Future<Output = ()>` cannot be sent between threads safely + needs_send(T::test2()); + //~^ ERROR `impl Future<Output = i32>` cannot be sent between threads safely +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs new file mode 100644 index 00000000000..96b623d6988 --- /dev/null +++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs @@ -0,0 +1,20 @@ +// run-rustfix +// edition: 2021 + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] +#![allow(unused)] + +trait Foo { + async fn test() -> () {} + async fn test2() -> i32 { 1 + 2 } +} + +fn bar<T: Foo>() { + fn needs_send(_: impl Send) {} + needs_send(T::test()); + //~^ ERROR `impl Future<Output = ()>` cannot be sent between threads safely + needs_send(T::test2()); + //~^ ERROR `impl Future<Output = i32>` cannot be sent between threads safely +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr new file mode 100644 index 00000000000..4319a14118b --- /dev/null +++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr @@ -0,0 +1,43 @@ +error[E0277]: `impl Future<Output = ()>` cannot be sent between threads safely + --> $DIR/send-on-async-fn-in-trait.rs:14:16 + | +LL | needs_send(T::test()); + | ---------- ^^^^^^^^^ `impl Future<Output = ()>` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `impl Future<Output = ()>` +note: required by a bound in `needs_send` + --> $DIR/send-on-async-fn-in-trait.rs:13:27 + | +LL | fn needs_send(_: impl Send) {} + | ^^^^ required by this bound in `needs_send` +help: `Send` can be made part of the associated future's guarantees for all implementations of `Foo::test` + | +LL - async fn test() -> () {} +LL + fn test() -> impl std::future::Future<Output = ()> + Send { async {} } + | + +error[E0277]: `impl Future<Output = i32>` cannot be sent between threads safely + --> $DIR/send-on-async-fn-in-trait.rs:16:16 + | +LL | needs_send(T::test2()); + | ---------- ^^^^^^^^^^ `impl Future<Output = i32>` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `impl Future<Output = i32>` +note: required by a bound in `needs_send` + --> $DIR/send-on-async-fn-in-trait.rs:13:27 + | +LL | fn needs_send(_: impl Send) {} + | ^^^^ required by this bound in `needs_send` +help: `Send` can be made part of the associated future's guarantees for all implementations of `Foo::test2` + | +LL - async fn test2() -> i32 { 1 + 2 } +LL + fn test2() -> impl std::future::Future<Output = i32> + Send {async { 1 + 2 } } + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs new file mode 100644 index 00000000000..83b69d72a96 --- /dev/null +++ b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs @@ -0,0 +1,15 @@ +// aux-build:foreign-async-fn.rs +// edition:2021 + +#![feature(async_fn_in_trait)] + +extern crate foreign_async_fn; +use foreign_async_fn::Foo; + +fn bar<T: Foo>() { + fn needs_send(_: impl Send) {} + needs_send(T::test()); + //~^ ERROR `impl Future<Output = ()>` cannot be sent between threads safely +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr new file mode 100644 index 00000000000..f337a04ba19 --- /dev/null +++ b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr @@ -0,0 +1,23 @@ +error[E0277]: `impl Future<Output = ()>` cannot be sent between threads safely + --> $DIR/send-on-foreign-async-fn-in-trait.rs:11:16 + | +LL | needs_send(T::test()); + | ---------- ^^^^^^^^^ `impl Future<Output = ()>` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `impl Future<Output = ()>` +note: `<T as Foo>::test` is an `async fn` in trait, which does not automatically imply that its future is `Send` + --> $DIR/auxiliary/foreign-async-fn.rs:6:5 + | +LL | async fn test(); + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `needs_send` + --> $DIR/send-on-foreign-async-fn-in-trait.rs:10:27 + | +LL | fn needs_send(_: impl Send) {} + | ^^^^ required by this bound in `needs_send` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/large_moves.attribute.stderr b/tests/ui/async-await/large_moves.attribute.stderr deleted file mode 100644 index 1d1999462ce..00000000000 --- a/tests/ui/async-await/large_moves.attribute.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error: moving 10024 bytes - --> $DIR/large_moves.rs:21:14 - | -LL | let z = (x, 42); - | ^ value moved from here - | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` -note: the lint level is defined here - --> $DIR/large_moves.rs:1:9 - | -LL | #![deny(large_assignments)] - | ^^^^^^^^^^^^^^^^^ - -error: moving 10024 bytes - --> $DIR/large_moves.rs:22:13 - | -LL | let a = z.0; - | ^^^ value moved from here - | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` - -error: moving 9999 bytes - --> $DIR/large_moves.rs:27:13 - | -LL | let _ = NotBox::new([0; 9999]); - | ^^^^^^^^^^^^^^^^^^^^^^ value moved from here - | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` - -error: moving 9999 bytes - --> $DIR/large_moves.rs:41:13 - | -LL | data, - | ^^^^ value moved from here - | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` - -error: aborting due to 4 previous errors - diff --git a/tests/ui/async-await/large_moves.option.stderr b/tests/ui/async-await/large_moves.option.stderr deleted file mode 100644 index 1d1999462ce..00000000000 --- a/tests/ui/async-await/large_moves.option.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error: moving 10024 bytes - --> $DIR/large_moves.rs:21:14 - | -LL | let z = (x, 42); - | ^ value moved from here - | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` -note: the lint level is defined here - --> $DIR/large_moves.rs:1:9 - | -LL | #![deny(large_assignments)] - | ^^^^^^^^^^^^^^^^^ - -error: moving 10024 bytes - --> $DIR/large_moves.rs:22:13 - | -LL | let a = z.0; - | ^^^ value moved from here - | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` - -error: moving 9999 bytes - --> $DIR/large_moves.rs:27:13 - | -LL | let _ = NotBox::new([0; 9999]); - | ^^^^^^^^^^^^^^^^^^^^^^ value moved from here - | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` - -error: moving 9999 bytes - --> $DIR/large_moves.rs:41:13 - | -LL | data, - | ^^^^ value moved from here - | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` - -error: aborting due to 4 previous errors - diff --git a/tests/ui/borrowck/issue-92157.rs b/tests/ui/borrowck/issue-92157.rs index 6ee2320a603..3a6f8908b21 100644 --- a/tests/ui/borrowck/issue-92157.rs +++ b/tests/ui/borrowck/issue-92157.rs @@ -9,7 +9,7 @@ extern {} #[lang = "start"] fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - //~^ ERROR: incorrect number of parameters for the `start` lang item + //~^ ERROR lang item `start` function has wrong type [E0308] 40+2 } diff --git a/tests/ui/borrowck/issue-92157.stderr b/tests/ui/borrowck/issue-92157.stderr index a4010d73d05..a46b1288911 100644 --- a/tests/ui/borrowck/issue-92157.stderr +++ b/tests/ui/borrowck/issue-92157.stderr @@ -1,11 +1,12 @@ -error: incorrect number of parameters for the `start` lang item +error[E0308]: lang item `start` function has wrong type --> $DIR/issue-92157.rs:11:1 | LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: the `start` lang item should have four parameters, but found 3 - = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _` + found signature `fn(fn() -> T, isize, *const *const u8) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/check-cfg/values-target-json.stderr b/tests/ui/check-cfg/values-target-json.stderr index e773d5d83cc..c705152d9fc 100644 --- a/tests/ui/check-cfg/values-target-json.stderr +++ b/tests/ui/check-cfg/values-target-json.stderr @@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")] | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `ericos`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `ericos`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 1f775814656..b381f5a4a0a 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")] | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index bfebf66701b..658a0b7b2a0 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -10,6 +10,66 @@ error[E0635]: unknown feature `const_cmp` LL | #![feature(const_cmp)] | ^^^^^^^^^ -error: aborting due to 2 previous errors +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:15:15 + | +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:15:15 + | +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:22:15 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:22:15 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:29:15 + | +LL | T: ~const FnOnce<()>, + | ^^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:29:15 + | +LL | T: ~const FnOnce<()>, + | ^^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:36:15 + | +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:36:15 + | +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:50:15 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:50:15 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^^^^ + +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0635`. diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.rs b/tests/ui/consts/unstable-const-fn-in-libcore.rs index 61e28117ed4..b62a74039f6 100644 --- a/tests/ui/consts/unstable-const-fn-in-libcore.rs +++ b/tests/ui/consts/unstable-const-fn-in-libcore.rs @@ -1,3 +1,5 @@ +// known-bug: #110395 +// FIXME check-pass // This is a non-regression test for const-qualification of unstable items in libcore // as explained in issue #67053. // const-qualification could miss some `const fn`s if they were unstable and the feature @@ -15,12 +17,12 @@ impl<T> Opt<T> { #[rustc_const_unstable(feature = "foo", issue = "none")] #[stable(feature = "rust1", since = "1.0.0")] const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { - //~^ ERROR destructor of - //~| ERROR destructor of + //FIXME ~^ ERROR destructor of + //FIXME ~| ERROR destructor of match self { Opt::Some(t) => t, Opt::None => f(), - //~^ ERROR cannot call + //FIXME ~^ ERROR cannot call } } } diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr index 95d7b7e8537..b75f99a720f 100644 --- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,34 +1,8 @@ -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/unstable-const-fn-in-libcore.rs:22:26 - | -LL | Opt::None => f(), - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: consider further restricting this bound - | -LL | const fn unwrap_or_else<F: ~const FnOnce() -> T + ~const std::ops::FnOnce<()>>(self, f: F) -> T { - | +++++++++++++++++++++++++++++ - -error[E0493]: destructor of `F` cannot be evaluated at compile-time - --> $DIR/unstable-const-fn-in-libcore.rs:17:60 - | -LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { - | ^ the destructor for this type cannot be evaluated in constant functions -... -LL | } - | - value is dropped here - -error[E0493]: destructor of `Opt<T>` cannot be evaluated at compile-time - --> $DIR/unstable-const-fn-in-libcore.rs:17:54 +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/unstable-const-fn-in-libcore.rs:19:39 | LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { - | ^^^^ the destructor for this type cannot be evaluated in constant functions -... -LL | } - | - value is dropped here + | ^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0015, E0493. -For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/entry-point/auxiliary/bad_main_functions.rs b/tests/ui/entry-point/auxiliary/bad_main_functions.rs new file mode 100644 index 00000000000..4649be99e6f --- /dev/null +++ b/tests/ui/entry-point/auxiliary/bad_main_functions.rs @@ -0,0 +1,2 @@ +pub fn boilerplate(x: u8) {} +//~^ ERROR: `main` function has wrong type [E0580] diff --git a/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs new file mode 100644 index 00000000000..0a115dd3b08 --- /dev/null +++ b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs @@ -0,0 +1,6 @@ +// aux-build:bad_main_functions.rs + +#![feature(imported_main)] + +extern crate bad_main_functions; +pub use bad_main_functions::boilerplate as main; diff --git a/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr new file mode 100644 index 00000000000..3c68933101c --- /dev/null +++ b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr @@ -0,0 +1,12 @@ +error[E0580]: `main` function has wrong type + --> $DIR/auxiliary/bad_main_functions.rs:1:1 + | +LL | pub fn boilerplate(x: u8) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters + | + = note: expected signature `fn()` + found signature `fn(u8)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0580`. diff --git a/tests/ui/error-codes/E0308.stderr b/tests/ui/error-codes/E0308.stderr index 187b775f92d..141abed6032 100644 --- a/tests/ui/error-codes/E0308.stderr +++ b/tests/ui/error-codes/E0308.stderr @@ -1,11 +1,11 @@ error[E0308]: intrinsic has wrong type - --> $DIR/E0308.rs:6:5 + --> $DIR/E0308.rs:6:20 | LL | fn size_of<T>(); - | ^^^^^^^^^^^^^^^^ expected `()`, found `usize` + | ^ expected `usize`, found `()` | - = note: expected fn pointer `extern "rust-intrinsic" fn()` - found fn pointer `extern "rust-intrinsic" fn() -> usize` + = note: expected signature `extern "rust-intrinsic" fn() -> usize` + found signature `extern "rust-intrinsic" fn()` error: aborting due to previous error diff --git a/tests/ui/extern/extern-main-fn.stderr b/tests/ui/extern/extern-main-fn.stderr index 136c9575382..846102670a8 100644 --- a/tests/ui/extern/extern-main-fn.stderr +++ b/tests/ui/extern/extern-main-fn.stderr @@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type LL | extern "C" fn main() {} | ^^^^^^^^^^^^^^^^^^^^ expected "Rust" fn, found "C" fn | - = note: expected fn pointer `fn()` - found fn pointer `extern "C" fn()` + = note: expected signature `fn()` + found signature `extern "C" fn()` error: aborting due to previous error diff --git a/tests/ui/fn/bad-main.stderr b/tests/ui/fn/bad-main.stderr index 675b66d0578..65140a0794f 100644 --- a/tests/ui/fn/bad-main.stderr +++ b/tests/ui/fn/bad-main.stderr @@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type LL | fn main(x: isize) { } | ^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn()` - found fn pointer `fn(isize)` + = note: expected signature `fn()` + found signature `fn(isize)` error: aborting due to previous error diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index 5fbba9a85ca..ada8fd7fa50 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,25 +1,8 @@ -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/normalize-tait-in-const.rs:26:5 - | -LL | fun(filter_positive()); - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: consider further restricting this bound - | -LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct + ~const std::ops::Fn<(&Alias<'_>,)>>(fun: F) { - | ++++++++++++++++++++++++++++++++++++ - -error[E0493]: destructor of `F` cannot be evaluated at compile-time - --> $DIR/normalize-tait-in-const.rs:25:79 +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/normalize-tait-in-const.rs:25:42 | LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^ the destructor for this type cannot be evaluated in constant functions -LL | fun(filter_positive()); -LL | } - | - value is dropped here + | ^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0015, E0493. -For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/inline-const/promotion.rs b/tests/ui/inline-const/promotion.rs new file mode 100644 index 00000000000..242959c6b51 --- /dev/null +++ b/tests/ui/inline-const/promotion.rs @@ -0,0 +1,22 @@ +#![feature(inline_const)] +#![allow(arithmetic_overflow, unconditional_panic)] + +// The only way to have promoteds that fail is in `const fn` called from `const`/`static`. +// Make sure that in a `const` block, we do not promote such calls. +const fn div_by_zero() -> i32 { + 1 / 0 +} + +const fn mk_false() -> bool { + false +} + +fn main() { + let v = const { + if mk_false() { + let _x: &'static i32 = &div_by_zero(); + //~^ ERROR: temporary value dropped while borrowed + } + 42 + }; +} diff --git a/tests/ui/inline-const/promotion.stderr b/tests/ui/inline-const/promotion.stderr new file mode 100644 index 00000000000..795fc8f5921 --- /dev/null +++ b/tests/ui/inline-const/promotion.stderr @@ -0,0 +1,14 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promotion.rs:17:37 + | +LL | let _x: &'static i32 = &div_by_zero(); + | ------------ ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index b99bb39d062..30b8a21269a 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs @@ -16,6 +16,7 @@ mod rusti { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "linux", target_os = "macos", diff --git a/tests/ui/issues/issue-9575.stderr b/tests/ui/issues/issue-9575.stderr index 5b8ce84a071..e49eac3babf 100644 --- a/tests/ui/issues/issue-9575.stderr +++ b/tests/ui/issues/issue-9575.stderr @@ -4,8 +4,8 @@ error[E0308]: `#[start]` function has wrong type LL | fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn(isize, *const *const u8) -> _` - found fn pointer `fn(isize, *const *const u8, *const u8) -> _` + = note: expected signature `fn(isize, *const *const u8) -> _` + found signature `fn(isize, *const *const u8, *const u8) -> _` error: aborting due to previous error diff --git a/tests/ui/lang-items/start_lang_item_args.argc.stderr b/tests/ui/lang-items/start_lang_item_args.argc.stderr index 65c99a93c75..66d4397a293 100644 --- a/tests/ui/lang-items/start_lang_item_args.argc.stderr +++ b/tests/ui/lang-items/start_lang_item_args.argc.stderr @@ -1,8 +1,12 @@ -error: parameter 2 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:75:38 | LL | fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ^^ help: change the type from `i8` to `isize` + | ^^ expected `isize`, found `i8` + | + = note: expected signature `fn(fn() -> _, isize, _, _) -> _` + found signature `fn(fn() -> _, i8, _, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.argv.stderr b/tests/ui/lang-items/start_lang_item_args.argv.stderr index f0947a9b3e9..53d776cd846 100644 --- a/tests/ui/lang-items/start_lang_item_args.argv.stderr +++ b/tests/ui/lang-items/start_lang_item_args.argv.stderr @@ -1,8 +1,12 @@ -error: parameter 3 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:89:52 | LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize { - | ^^ help: change the type from `u8` to `*const *const u8` + | ^^ expected `*const *const u8`, found `u8` + | + = note: expected signature `fn(fn() -> _, _, *const *const u8, _) -> _` + found signature `fn(fn() -> _, _, u8, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr index 08efd5088f9..7d002e090b5 100644 --- a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr +++ b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr @@ -1,13 +1,12 @@ -error: parameter 3 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:82:52 | LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ expected `u8`, found `usize` | -help: change the type from `*const *const usize` to `*const *const u8` - | -LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ~~~~~~~~~~~~~~~~ + = note: expected signature `fn(fn() -> _, _, *const *const u8, _) -> _` + found signature `fn(fn() -> _, _, *const *const usize, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.main_args.stderr b/tests/ui/lang-items/start_lang_item_args.main_args.stderr index c20a744661d..91994b9d742 100644 --- a/tests/ui/lang-items/start_lang_item_args.main_args.stderr +++ b/tests/ui/lang-items/start_lang_item_args.main_args.stderr @@ -1,13 +1,12 @@ -error: parameter 1 of the `start` lang item is incorrect - --> $DIR/start_lang_item_args.rs:61:20 +error[E0308]: lang item `start` function has wrong type + --> $DIR/start_lang_item_args.rs:61:1 | LL | fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | -help: change the type from `fn(i32) -> T` to `fn() -> T` - | -LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ~~~~~~~~~ + = note: expected signature `fn(fn() -> _, _, _, _) -> _` + found signature `fn(fn(i32) -> _, _, _, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr index 8f967252f49..4582b69850c 100644 --- a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr +++ b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr @@ -1,13 +1,14 @@ -error: parameter 1 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:68:20 | LL | fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ^^^^^^^^^^^ + | - ^^^^^^^^^^^ expected type parameter `T`, found `u16` + | | + | this type parameter | -help: change the type from `fn() -> u16` to `fn() -> T` - | -LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ~~~~~~~~~ + = note: expected signature `fn(fn() -> T, _, _, _) -> _` + found signature `fn(fn() -> u16, _, _, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr index deb37b868ea..87940d05e78 100644 --- a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr +++ b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr @@ -1,8 +1,12 @@ -error: parameter 1 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:54:20 | LL | fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ^^^ help: change the type from `u64` to `fn() -> T` + | ^^^ expected fn pointer, found `u64` + | + = note: expected signature `fn(fn() -> T, _, _, _) -> _` + found signature `fn(u64, _, _, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr index 004c2a67f62..5363871e202 100644 --- a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr +++ b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr @@ -1,11 +1,12 @@ -error: incorrect number of parameters for the `start` lang item +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:15:1 | LL | fn start<T>() -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: the `start` lang item should have four parameters, but found 0 - = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _` + found signature `fn() -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr index 1d8285b5900..2bb29f911a1 100644 --- a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr +++ b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr @@ -1,8 +1,12 @@ -error: the return type of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:29:84 | LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {} - | ^ help: change the type from `()` to `isize` + | ^ expected `isize`, found `()` + | + = note: expected signature `fn(fn() -> _, _, _, _) -> isize` + found signature `fn(fn() -> _, _, _, _)` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr index e545a750f24..f873f7614bd 100644 --- a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr +++ b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr @@ -1,11 +1,12 @@ -error: incorrect number of parameters for the `start` lang item +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:22:1 | LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: the `start` lang item should have four parameters, but found 3 - = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _` + found signature `fn(fn() -> T, isize, *const *const u8) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.rs b/tests/ui/lang-items/start_lang_item_args.rs index 0dbfba39cb6..4a0302bcb15 100644 --- a/tests/ui/lang-items/start_lang_item_args.rs +++ b/tests/ui/lang-items/start_lang_item_args.rs @@ -13,33 +13,33 @@ pub trait Sized {} #[cfg(missing_all_args)] #[lang = "start"] fn start<T>() -> isize { - //[missing_all_args]~^ ERROR incorrect number of parameters + //[missing_all_args]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(missing_sigpipe_arg)] #[lang = "start"] fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - //[missing_sigpipe_arg]~^ ERROR incorrect number of parameters + //[missing_sigpipe_arg]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(missing_ret)] #[lang = "start"] fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {} -//[missing_ret]~^ ERROR the return type of the `start` lang item is incorrect +//[missing_ret]~^ ERROR lang item `start` function has wrong type [E0308] #[cfg(start_ret)] #[lang = "start"] fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 { - //[start_ret]~^ ERROR the return type of the `start` lang item is incorrect + //[start_ret]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(too_many_args)] #[lang = "start"] fn start<T>( - //[too_many_args]~^ ERROR incorrect number of parameters + //[too_many_args]~^ ERROR lang item `start` function has wrong type [E0308] _main: fn() -> T, _argc: isize, _argv: *const *const u8, @@ -52,49 +52,49 @@ fn start<T>( #[cfg(main_ty)] #[lang = "start"] fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - //[main_ty]~^ ERROR parameter 1 of the `start` lang item is incorrect + //[main_ty]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(main_args)] #[lang = "start"] fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - //[main_args]~^ ERROR parameter 1 of the `start` lang item is incorrect + //[main_args]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(main_ret)] #[lang = "start"] fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - //[main_ret]~^ ERROR parameter 1 of the `start` lang item is incorrect + //[main_ret]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(argc)] #[lang = "start"] fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize { - //[argc]~^ ERROR parameter 2 of the `start` lang item is incorrect + //[argc]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(argv_inner_ptr)] #[lang = "start"] fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize { - //[argv_inner_ptr]~^ ERROR parameter 3 of the `start` lang item is incorrect + //[argv_inner_ptr]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(argv)] #[lang = "start"] fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize { - //[argv]~^ ERROR parameter 3 of the `start` lang item is incorrect + //[argv]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(sigpipe)] #[lang = "start"] fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize { - //[sigpipe]~^ ERROR parameter 4 of the `start` lang item is incorrect + //[sigpipe]~^ ERROR lang item `start` function has wrong type [E0308] 100 } diff --git a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr index b20ae312801..280d423bd7e 100644 --- a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr +++ b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr @@ -1,8 +1,12 @@ -error: parameter 4 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:96:80 | LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize { - | ^^^ help: change the type from `i64` to `u8` + | ^^^ expected `u8`, found `i64` + | + = note: expected signature `fn(fn() -> _, _, _, u8) -> _` + found signature `fn(fn() -> _, _, _, i64) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr index 935d5f3c8b4..4e4f8a5cdb3 100644 --- a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr +++ b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr @@ -1,8 +1,12 @@ -error: the return type of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:34:87 | LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 { - | ^^ help: change the type from `u8` to `isize` + | ^^ expected `isize`, found `u8` + | + = note: expected signature `fn(fn() -> _, _, _, _) -> isize` + found signature `fn(fn() -> _, _, _, _) -> u8` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr index 30a7ed18a3d..085d4b1f238 100644 --- a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr +++ b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr @@ -1,4 +1,4 @@ -error: incorrect number of parameters for the `start` lang item +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:41:1 | LL | / fn start<T>( @@ -8,10 +8,11 @@ LL | | _argc: isize, ... | LL | | _extra_arg: (), LL | | ) -> isize { - | |__________^ + | |__________^ incorrect number of function parameters | - = note: the `start` lang item should have four parameters, but found 5 - = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _` + found signature `fn(fn() -> T, isize, *const *const u8, u8, ()) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.rs b/tests/ui/lang-items/start_lang_item_with_target_feature.rs new file mode 100644 index 00000000000..3052b7bb563 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_with_target_feature.rs @@ -0,0 +1,19 @@ +// only-x86_64 +// check-fail + +#![feature(lang_items, no_core, target_feature_11)] +#![no_core] + +#[lang = "copy"] +pub trait Copy {} +#[lang = "sized"] +pub trait Sized {} + +#[lang = "start"] +#[target_feature(enable = "avx2")] +//~^ ERROR `start` language item function is not allowed to have `#[target_feature]` +fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + 0 +} + +fn main() {} diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.stderr b/tests/ui/lang-items/start_lang_item_with_target_feature.stderr new file mode 100644 index 00000000000..ff55a1365e4 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_with_target_feature.stderr @@ -0,0 +1,11 @@ +error: `start` language item function is not allowed to have `#[target_feature]` + --> $DIR/start_lang_item_with_target_feature.rs:13:1 + | +LL | #[target_feature(enable = "avx2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + | ------------------------------------------------------------------------------------------- `start` language item function is not allowed to have `#[target_feature]` + +error: aborting due to previous error + diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs index 9c8c636812e..43ceffb71e5 100644 --- a/tests/ui/lint/invalid_from_utf8.rs +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -1,6 +1,8 @@ // check-pass +#![feature(inline_const)] #![feature(concat_bytes)] + #![warn(invalid_from_utf8_unchecked)] #![warn(invalid_from_utf8)] @@ -90,4 +92,29 @@ pub fn from_utf8() { } } +pub fn from_utf8_with_indirections() { + let mut a = [99, 108, 130, 105, 112, 112, 121]; + std::str::from_utf8_mut(&mut a); + //~^ WARN calls to `std::str::from_utf8_mut` + let mut b = &mut a; + let mut c = b; + std::str::from_utf8_mut(c); + //~^ WARN calls to `std::str::from_utf8_mut` + let mut c = &[99, 108, 130, 105, 112, 112, 121]; + std::str::from_utf8(c); + //~^ WARN calls to `std::str::from_utf8` + const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; + std::str::from_utf8(&INVALID_1); + //~^ WARN calls to `std::str::from_utf8` + static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; + std::str::from_utf8(&INVALID_2); + //~^ WARN calls to `std::str::from_utf8` + const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121]; + std::str::from_utf8(INVALID_3); + //~^ WARN calls to `std::str::from_utf8` + const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] }; + std::str::from_utf8(INVALID_4); + //~^ WARN calls to `std::str::from_utf8` +} + fn main() {} diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr index 8e00d3bf872..884165d4f12 100644 --- a/tests/ui/lint/invalid_from_utf8.stderr +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -1,43 +1,43 @@ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:19:9 + --> $DIR/invalid_from_utf8.rs:21:9 | LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes | note: the lint level is defined here - --> $DIR/invalid_from_utf8.rs:4:9 + --> $DIR/invalid_from_utf8.rs:6:9 | LL | #![warn(invalid_from_utf8_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:21:9 + --> $DIR/invalid_from_utf8.rs:23:9 | LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:39:9 + --> $DIR/invalid_from_utf8.rs:41:9 | LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:41:9 + --> $DIR/invalid_from_utf8.rs:43:9 | LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:43:9 + --> $DIR/invalid_from_utf8.rs:45:9 | LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ @@ -45,7 +45,7 @@ LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:45:9 + --> $DIR/invalid_from_utf8.rs:47:9 | LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ @@ -53,45 +53,45 @@ LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:62:9 + --> $DIR/invalid_from_utf8.rs:64:9 | LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes | note: the lint level is defined here - --> $DIR/invalid_from_utf8.rs:5:9 + --> $DIR/invalid_from_utf8.rs:7:9 | LL | #![warn(invalid_from_utf8)] | ^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:64:9 + --> $DIR/invalid_from_utf8.rs:66:9 | LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:82:9 + --> $DIR/invalid_from_utf8.rs:84:9 | LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^-----------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:84:9 + --> $DIR/invalid_from_utf8.rs:86:9 | LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:86:9 + --> $DIR/invalid_from_utf8.rs:88:9 | LL | std::str::from_utf8(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^-------------^ @@ -99,12 +99,69 @@ LL | std::str::from_utf8(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:88:9 + --> $DIR/invalid_from_utf8.rs:90:9 | LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^---------------------------------^ | | | the literal was valid UTF-8 up to the 2 bytes -warning: 12 warnings emitted +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:97:5 + | +LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8_mut(&mut a); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:101:5 + | +LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +... +LL | std::str::from_utf8_mut(c); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:104:5 + | +LL | let mut c = &[99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(c); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:107:5 + | +LL | const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(&INVALID_1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:110:5 + | +LL | static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(&INVALID_2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:113:5 + | +LL | const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(INVALID_3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:116:5 + | +LL | const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] }; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(INVALID_4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 19 warnings emitted diff --git a/tests/ui/async-await/large_moves.rs b/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs index 62b12104694..33113642023 100644 --- a/tests/ui/async-await/large_moves.rs +++ b/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs @@ -1,10 +1,8 @@ #![deny(large_assignments)] #![feature(large_assignments)] -#![cfg_attr(attribute, move_size_limit = "1000")] +#![move_size_limit = "1000"] // build-fail // only-x86_64 -// revisions: attribute option -// [option]compile-flags: -Zmove-size-limit=1000 // edition:2018 // compile-flags: -Zmir-opt-level=0 @@ -12,25 +10,12 @@ use std::{sync::Arc, rc::Rc}; fn main() { - let x = async { - let y = [0; 9999]; - dbg!(y); - thing(&y).await; - dbg!(y); - }; - let z = (x, 42); //~ ERROR large_assignments - let a = z.0; //~ ERROR large_assignments - let b = z.1; let _ = Arc::new([0; 9999]); // OK! let _ = Box::new([0; 9999]); // OK! let _ = Rc::new([0; 9999]); // OK! let _ = NotBox::new([0; 9999]); //~ ERROR large_assignments } -async fn thing(y: &[u8]) { - dbg!(y); -} - struct NotBox { data: [u8; 9999], } diff --git a/tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr b/tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr new file mode 100644 index 00000000000..b45cbe5da4d --- /dev/null +++ b/tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr @@ -0,0 +1,23 @@ +error: moving 9999 bytes + --> $DIR/box_rc_arc_allowed.rs:16:13 + | +LL | let _ = NotBox::new([0; 9999]); + | ^^^^^^^^^^^^^^^^^^^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` +note: the lint level is defined here + --> $DIR/box_rc_arc_allowed.rs:1:9 + | +LL | #![deny(large_assignments)] + | ^^^^^^^^^^^^^^^^^ + +error: moving 9999 bytes + --> $DIR/box_rc_arc_allowed.rs:26:13 + | +LL | data, + | ^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/large_assignments/large_future.attribute.stderr b/tests/ui/lint/large_assignments/large_future.attribute.stderr new file mode 100644 index 00000000000..734b7ff7ba2 --- /dev/null +++ b/tests/ui/lint/large_assignments/large_future.attribute.stderr @@ -0,0 +1,23 @@ +error: moving 10024 bytes + --> $DIR/large_future.rs:19:14 + | +LL | let z = (x, 42); + | ^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` +note: the lint level is defined here + --> $DIR/large_future.rs:1:9 + | +LL | #![deny(large_assignments)] + | ^^^^^^^^^^^^^^^^^ + +error: moving 10024 bytes + --> $DIR/large_future.rs:20:13 + | +LL | let a = z.0; + | ^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/large_assignments/large_future.option.stderr b/tests/ui/lint/large_assignments/large_future.option.stderr new file mode 100644 index 00000000000..734b7ff7ba2 --- /dev/null +++ b/tests/ui/lint/large_assignments/large_future.option.stderr @@ -0,0 +1,23 @@ +error: moving 10024 bytes + --> $DIR/large_future.rs:19:14 + | +LL | let z = (x, 42); + | ^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` +note: the lint level is defined here + --> $DIR/large_future.rs:1:9 + | +LL | #![deny(large_assignments)] + | ^^^^^^^^^^^^^^^^^ + +error: moving 10024 bytes + --> $DIR/large_future.rs:20:13 + | +LL | let a = z.0; + | ^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/large_assignments/large_future.rs b/tests/ui/lint/large_assignments/large_future.rs new file mode 100644 index 00000000000..834746fa97e --- /dev/null +++ b/tests/ui/lint/large_assignments/large_future.rs @@ -0,0 +1,26 @@ +#![deny(large_assignments)] +#![cfg_attr(attribute, feature(large_assignments))] +#![cfg_attr(attribute, move_size_limit = "1000")] +// build-fail +// only-x86_64 +// revisions: attribute option +// [option]compile-flags: -Zmove-size-limit=1000 + +// edition:2018 +// compile-flags: -Zmir-opt-level=0 + +fn main() { + let x = async { + let y = [0; 9999]; + dbg!(y); + thing(&y).await; + dbg!(y); + }; + let z = (x, 42); //~ ERROR large_assignments + let a = z.0; //~ ERROR large_assignments + let b = z.1; +} + +async fn thing(y: &[u8]) { + dbg!(y); +} diff --git a/tests/ui/main-wrong-type.stderr b/tests/ui/main-wrong-type.stderr index 43efaf884e3..1e5f368758e 100644 --- a/tests/ui/main-wrong-type.stderr +++ b/tests/ui/main-wrong-type.stderr @@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type LL | fn main(foo: S) { | ^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn()` - found fn pointer `fn(S)` + = note: expected signature `fn()` + found signature `fn(S)` error: aborting due to previous error diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.rs b/tests/ui/panic-handler/panic-handler-bad-signature-1.rs index 775961d3fd7..ae27db7a835 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-1.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.rs @@ -6,8 +6,5 @@ use core::panic::PanicInfo; #[panic_handler] -fn panic( - info: PanicInfo, //~ ERROR argument should be `&PanicInfo` -) -> () //~ ERROR return type should be `!` -{ -} +fn panic(info: PanicInfo) -> () {} +//~^ `#[panic_handler]` function has wrong type [E0308] diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr index 8b044f7669c..d12bfbf269e 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr @@ -1,14 +1,12 @@ -error: return type should be `!` - --> $DIR/panic-handler-bad-signature-1.rs:11:6 +error[E0308]: `#[panic_handler]` function has wrong type + --> $DIR/panic-handler-bad-signature-1.rs:9:16 | -LL | ) -> () - | ^^ - -error: argument should be `&PanicInfo` - --> $DIR/panic-handler-bad-signature-1.rs:10:11 +LL | fn panic(info: PanicInfo) -> () {} + | ^^^^^^^^^ expected `&PanicInfo<'_>`, found `PanicInfo<'_>` | -LL | info: PanicInfo, - | ^^^^^^^^^ + = note: expected signature `fn(&PanicInfo<'_>) -> !` + found signature `fn(PanicInfo<'_>)` -error: aborting due to 2 previous errors +error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.rs b/tests/ui/panic-handler/panic-handler-bad-signature-2.rs index 72793400058..3c3f1513f6f 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-2.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.rs @@ -6,9 +6,8 @@ use core::panic::PanicInfo; #[panic_handler] -fn panic( - info: &'static PanicInfo, //~ ERROR argument should be `&PanicInfo` -) -> ! +fn panic(info: &'static PanicInfo) -> ! +//~^ #[panic_handler]` function has wrong type [E0308] { loop {} } diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr index 5ab6934202e..06e32d5fb84 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr @@ -1,8 +1,12 @@ -error: argument should be `&PanicInfo` - --> $DIR/panic-handler-bad-signature-2.rs:10:11 +error[E0308]: `#[panic_handler]` function has wrong type + --> $DIR/panic-handler-bad-signature-2.rs:9:1 | -LL | info: &'static PanicInfo, - | ^^^^^^^^^^^^^^^^^^ +LL | fn panic(info: &'static PanicInfo) -> ! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected fn pointer `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _` + found fn pointer `for<'a> fn(&'static PanicInfo<'a>) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-3.rs b/tests/ui/panic-handler/panic-handler-bad-signature-3.rs index ab9c9d7f417..9e17e32fbb4 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-3.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-3.rs @@ -6,6 +6,6 @@ use core::panic::PanicInfo; #[panic_handler] -fn panic() -> ! { //~ ERROR function should have one argument +fn panic() -> ! { //~ #[panic_handler]` function has wrong type [E0308] loop {} } diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr index 0a70181fdac..8365f5769eb 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr @@ -1,8 +1,12 @@ -error: function should have one argument +error[E0308]: `#[panic_handler]` function has wrong type --> $DIR/panic-handler-bad-signature-3.rs:9:1 | LL | fn panic() -> ! { - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ incorrect number of function parameters + | + = note: expected signature `fn(&PanicInfo<'_>) -> _` + found signature `fn() -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.rs b/tests/ui/panic-handler/panic-handler-bad-signature-5.rs new file mode 100644 index 00000000000..97307d1b2a4 --- /dev/null +++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.rs @@ -0,0 +1,13 @@ +// compile-flags:-C panic=abort + +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_handler] +fn panic(info: &PanicInfo<'static>) -> ! +//~^ #[panic_handler]` function has wrong type [E0308] +{ + loop {} +} diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr new file mode 100644 index 00000000000..22b8d5ca811 --- /dev/null +++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr @@ -0,0 +1,12 @@ +error[E0308]: `#[panic_handler]` function has wrong type + --> $DIR/panic-handler-bad-signature-5.rs:9:1 + | +LL | fn panic(info: &PanicInfo<'static>) -> ! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected fn pointer `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _` + found fn pointer `for<'a> fn(&'a PanicInfo<'static>) -> _` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/panic-handler/panic-handler-with-target-feature.rs b/tests/ui/panic-handler/panic-handler-with-target-feature.rs new file mode 100644 index 00000000000..8ea0275d7e9 --- /dev/null +++ b/tests/ui/panic-handler/panic-handler-with-target-feature.rs @@ -0,0 +1,15 @@ +// compile-flags:-C panic=abort +// only-x86_64 + +#![feature(target_feature_11)] +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_handler] +#[target_feature(enable = "avx2")] +//~^ ERROR `panic_impl` language item function is not allowed to have `#[target_feature]` +fn panic(info: &PanicInfo) -> ! { + unimplemented!(); +} diff --git a/tests/ui/panic-handler/panic-handler-with-target-feature.stderr b/tests/ui/panic-handler/panic-handler-with-target-feature.stderr new file mode 100644 index 00000000000..4210a4200ae --- /dev/null +++ b/tests/ui/panic-handler/panic-handler-with-target-feature.stderr @@ -0,0 +1,11 @@ +error: `panic_impl` language item function is not allowed to have `#[target_feature]` + --> $DIR/panic-handler-with-target-feature.rs:11:1 + | +LL | #[target_feature(enable = "avx2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn panic(info: &PanicInfo) -> ! { + | ------------------------------- `panic_impl` language item function is not allowed to have `#[target_feature]` + +error: aborting due to previous error + diff --git a/tests/ui/parser/issues/issue-98601-delimiter-error-1.rs b/tests/ui/parser/issues/issue-98601-delimiter-error-1.rs new file mode 100644 index 00000000000..cfbbd014d4f --- /dev/null +++ b/tests/ui/parser/issues/issue-98601-delimiter-error-1.rs @@ -0,0 +1,9 @@ +fn foo() { + match 0 { + _ => {} + } + if foo + } +} //~ ERROR unexpected closing delimiter: `}` + +fn main() {} diff --git a/tests/ui/parser/issues/issue-98601-delimiter-error-1.stderr b/tests/ui/parser/issues/issue-98601-delimiter-error-1.stderr new file mode 100644 index 00000000000..d568a4c583a --- /dev/null +++ b/tests/ui/parser/issues/issue-98601-delimiter-error-1.stderr @@ -0,0 +1,16 @@ +error: unexpected closing delimiter: `}` + --> $DIR/issue-98601-delimiter-error-1.rs:7:1 + | +LL | fn foo() { + | - this delimiter might not be properly closed... +LL | match 0 { +LL | _ => {} + | -- block is empty, you might have not meant to close it +... +LL | } + | - ...as it matches this but it has different indentation +LL | } + | ^ unexpected closing delimiter + +error: aborting due to previous error + diff --git a/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs b/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs new file mode 100644 index 00000000000..254e816cfc9 --- /dev/null +++ b/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs @@ -0,0 +1,5 @@ +fn main() { + todo!(); +} + +fn other(_: i32)) {} //~ ERROR unexpected closing delimiter: `)` diff --git a/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.stderr b/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.stderr new file mode 100644 index 00000000000..81dd39bb769 --- /dev/null +++ b/tests/ui/parser/issues/issue-98601-delimiter-error-unexpected-close.stderr @@ -0,0 +1,14 @@ +error: unexpected closing delimiter: `)` + --> $DIR/issue-98601-delimiter-error-unexpected-close.rs:5:17 + | +LL | fn main() { + | - this opening brace... +LL | todo!(); +LL | } + | - ...matches this closing brace +LL | +LL | fn other(_: i32)) {} + | ^ unexpected closing delimiter + +error: aborting due to previous error + diff --git a/tests/ui/range/issue-54505-no-std.rs b/tests/ui/range/issue-54505-no-std.rs index db455fada3b..a1595685372 100644 --- a/tests/ui/range/issue-54505-no-std.rs +++ b/tests/ui/range/issue-54505-no-std.rs @@ -17,9 +17,9 @@ extern "C" fn eh_personality() {} static EH_CATCH_TYPEINFO: u8 = 0; #[panic_handler] -fn panic_handler() {} -//~^ ERROR return type should be `!` -//~| ERROR function should have one argument +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + unimplemented!(); +} // take a reference to any built-in range fn take_range(_r: &impl RangeBounds<i8>) {} diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr index 13563d1940c..1694d514f42 100644 --- a/tests/ui/range/issue-54505-no-std.stderr +++ b/tests/ui/range/issue-54505-no-std.stderr @@ -1,15 +1,3 @@ -error: return type should be `!` - --> $DIR/issue-54505-no-std.rs:20:20 - | -LL | fn panic_handler() {} - | ^ - -error: function should have one argument - --> $DIR/issue-54505-no-std.rs:20:1 - | -LL | fn panic_handler() {} - | ^^^^^^^^^^^^^^^^^^ - error[E0308]: mismatched types --> $DIR/issue-54505-no-std.rs:29:16 | @@ -130,6 +118,6 @@ help: consider borrowing here LL | take_range(&(..=42)); | ++ + -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/resolve/bad-expr-path.stderr b/tests/ui/resolve/bad-expr-path.stderr index 411130913c8..0392c1fa239 100644 --- a/tests/ui/resolve/bad-expr-path.stderr +++ b/tests/ui/resolve/bad-expr-path.stderr @@ -16,8 +16,8 @@ error[E0580]: `main` function has wrong type LL | fn main(arguments: Vec<String>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn()` - found fn pointer `fn(Vec<String>)` + = note: expected signature `fn()` + found signature `fn(Vec<String>)` error[E0425]: cannot find function `log` in this scope --> $DIR/bad-expr-path.rs:4:5 diff --git a/tests/ui/resolve/bad-expr-path2.stderr b/tests/ui/resolve/bad-expr-path2.stderr index af3ca99c510..9238b1f7023 100644 --- a/tests/ui/resolve/bad-expr-path2.stderr +++ b/tests/ui/resolve/bad-expr-path2.stderr @@ -16,8 +16,8 @@ error[E0580]: `main` function has wrong type LL | fn main(arguments: Vec<String>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn()` - found fn pointer `fn(Vec<String>)` + = note: expected signature `fn()` + found signature `fn(Vec<String>)` error[E0425]: cannot find function `log` in this scope --> $DIR/bad-expr-path2.rs:6:5 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs index 2c99d8bf1c6..15f062edf0e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs @@ -1,4 +1,5 @@ -// check-pass +// known-bug: #110395 +// FIXME check-pass #![feature(const_trait_impl, const_closures)] #![allow(incomplete_features)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr new file mode 100644 index 00000000000..f25390a9070 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr @@ -0,0 +1,8 @@ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-closure-parse-not-item.rs:7:32 + | +LL | const fn test() -> impl ~const Fn() { + | ^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr index 96ffca6519a..4c45b0e56c6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr @@ -1,15 +1,8 @@ -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closure-trait-method-fail.rs:15:5 +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-closure-trait-method-fail.rs:14:39 | -LL | x(()) - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: consider further restricting this bound - | -LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const std::ops::FnOnce<((),)>>(x: T) -> i32 { - | ++++++++++++++++++++++++++++++++ +LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { + | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr index fd0c2911814..a8ef244ea30 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr @@ -1,15 +1,8 @@ -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closure-trait-method.rs:15:5 +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-closure-trait-method.rs:14:39 | -LL | x(()) - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: consider further restricting this bound - | -LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const std::ops::FnOnce<((),)>>(x: T) -> i32 { - | ++++++++++++++++++++++++++++++++ +LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { + | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr index abf2a2dc511..6d61b23e4b7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr @@ -1,39 +1,26 @@ -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closures.rs:12:5 +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-closures.rs:8:19 | -LL | f() * 7 - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: consider further restricting this bound - | -LL | F: ~const FnOnce() -> u8 + ~const std::ops::Fn<()>, - | +++++++++++++++++++++++++ +LL | F: ~const FnOnce() -> u8, + | ^^^^^^^^^^^^^^ -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closures.rs:24:5 - | -LL | f() + f() - | ^^^ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-closures.rs:9:19 | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: consider further restricting this bound - | -LL | const fn answer<F: ~const Fn() -> u8 + ~const std::ops::Fn<()>>(f: &F) -> u8 { - | +++++++++++++++++++++++++ +LL | F: ~const FnMut() -> u8, + | ^^^^^^^^^^^^^ -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closures.rs:24:11 - | -LL | f() + f() - | ^^^ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-closures.rs:10:19 | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: consider further restricting this bound +LL | F: ~const Fn() -> u8, + | ^^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-closures.rs:23:27 | -LL | const fn answer<F: ~const Fn() -> u8 + ~const std::ops::Fn<()>>(f: &F) -> u8 { - | +++++++++++++++++++++++++ +LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 { + | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs new file mode 100644 index 00000000000..2f474d978d3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs @@ -0,0 +1,11 @@ +// check-pass +#![feature(const_trait_impl, effects)] + +const fn a() {} + +fn foo<F: FnOnce()>(a: F) {} + +fn main() { + let _ = a; + foo(a); +} diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index d723ff538a8..813e65e45a2 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -146,33 +146,33 @@ hir-stats - Trait 192 ( 2.1%) 4 hir-stats WherePredicate 192 ( 2.1%) 3 64 hir-stats - BoundPredicate 192 ( 2.1%) 3 hir-stats Block 288 ( 3.2%) 6 48 -hir-stats Pat 360 ( 4.0%) 5 72 +hir-stats Pat 360 ( 3.9%) 5 72 hir-stats - Wild 72 ( 0.8%) 1 hir-stats - Struct 72 ( 0.8%) 1 hir-stats - Binding 216 ( 2.4%) 3 hir-stats GenericParam 400 ( 4.4%) 5 80 -hir-stats Generics 560 ( 6.2%) 10 56 -hir-stats Ty 720 ( 8.0%) 15 48 +hir-stats Generics 560 ( 6.1%) 10 56 +hir-stats Ty 720 ( 7.9%) 15 48 hir-stats - Ptr 48 ( 0.5%) 1 hir-stats - Ref 48 ( 0.5%) 1 -hir-stats - Path 624 ( 6.9%) 13 -hir-stats Expr 768 ( 8.5%) 12 64 +hir-stats - Path 624 ( 6.8%) 13 +hir-stats Expr 768 ( 8.4%) 12 64 hir-stats - Path 64 ( 0.7%) 1 hir-stats - Struct 64 ( 0.7%) 1 hir-stats - Match 64 ( 0.7%) 1 hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Lit 128 ( 1.4%) 2 hir-stats - Block 384 ( 4.2%) 6 -hir-stats Item 880 ( 9.7%) 11 80 -hir-stats - Trait 80 ( 0.9%) 1 -hir-stats - Enum 80 ( 0.9%) 1 -hir-stats - ExternCrate 80 ( 0.9%) 1 -hir-stats - ForeignMod 80 ( 0.9%) 1 -hir-stats - Impl 80 ( 0.9%) 1 -hir-stats - Fn 160 ( 1.8%) 2 -hir-stats - Use 320 ( 3.5%) 4 -hir-stats Path 1_240 (13.7%) 31 40 -hir-stats PathSegment 1_920 (21.2%) 40 48 +hir-stats Item 968 (10.6%) 11 88 +hir-stats - Trait 88 ( 1.0%) 1 +hir-stats - Enum 88 ( 1.0%) 1 +hir-stats - ExternCrate 88 ( 1.0%) 1 +hir-stats - ForeignMod 88 ( 1.0%) 1 +hir-stats - Impl 88 ( 1.0%) 1 +hir-stats - Fn 176 ( 1.9%) 2 +hir-stats - Use 352 ( 3.9%) 4 +hir-stats Path 1_240 (13.6%) 31 40 +hir-stats PathSegment 1_920 (21.0%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 9_048 +hir-stats Total 9_136 hir-stats diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs index f21c9b2c808..c3b201fb1c6 100644 --- a/tests/ui/structs-enums/rec-align-u64.rs +++ b/tests/ui/structs-enums/rec-align-u64.rs @@ -37,6 +37,7 @@ struct Outer { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "linux", target_os = "macos", diff --git a/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.rs b/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.rs new file mode 100644 index 00000000000..fec0fdc46fb --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.rs @@ -0,0 +1,9 @@ +#![feature(type_alias_impl_trait)] + +pub type Tait = impl Iterator<Item = (&'db Key, impl Iterator)>; +//~^ ERROR use of undeclared lifetime name `'db` +//~| ERROR cannot find type `Key` in this scope +//~| ERROR unconstrained opaque type +//~| ERROR unconstrained opaque type + +pub fn main() {} diff --git a/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr b/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr new file mode 100644 index 00000000000..d4aeace4ae7 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr @@ -0,0 +1,47 @@ +error[E0261]: use of undeclared lifetime name `'db` + --> $DIR/nested-impl-trait-in-tait.rs:3:40 + | +LL | pub type Tait = impl Iterator<Item = (&'db Key, impl Iterator)>; + | ^^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'db` lifetime + | +LL | pub type Tait = impl for<'db> Iterator<Item = (&'db Key, impl Iterator)>; + | ++++++++ +help: consider introducing lifetime `'db` here + | +LL | pub type Tait<'db> = impl Iterator<Item = (&'db Key, impl Iterator)>; + | +++++ + +error[E0412]: cannot find type `Key` in this scope + --> $DIR/nested-impl-trait-in-tait.rs:3:44 + | +LL | pub type Tait = impl Iterator<Item = (&'db Key, impl Iterator)>; + | ^^^ not found in this scope + | +help: consider importing this struct + | +LL + use std::thread::local_impl::Key; + | + +error: unconstrained opaque type + --> $DIR/nested-impl-trait-in-tait.rs:3:17 + | +LL | pub type Tait = impl Iterator<Item = (&'db Key, impl Iterator)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Tait` must be used in combination with a concrete type within the same module + +error: unconstrained opaque type + --> $DIR/nested-impl-trait-in-tait.rs:3:49 + | +LL | pub type Tait = impl Iterator<Item = (&'db Key, impl Iterator)>; + | ^^^^^^^^^^^^^ + | + = note: `Tait` must be used in combination with a concrete type within the same module + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0261, E0412. +For more information about an error, try `rustc --explain E0261`. |
