diff --git a/compiler/rustc_attr_ir/src/data_structures.rs b/compiler/rustc_attr_ir/src/data_structures.rs index 3d715c6a8a291..b3e2c617aac41 100644 --- a/compiler/rustc_attr_ir/src/data_structures.rs +++ b/compiler/rustc_attr_ir/src/data_structures.rs @@ -70,42 +70,6 @@ pub enum CguFields { ExpectedCguReuse { cfg: Symbol, module: Symbol, kind: CguKind }, } -#[derive(Copy, Clone, PartialEq, Debug, PrintAttribute)] -#[derive(StableHash, Encodable, Decodable)] -pub enum DivergingFallbackBehavior { - /// Always fallback to `()` (aka "always spontaneous decay") - ToUnit, - /// Always fallback to `!` (which should be equivalent to never falling back + not making - /// never-to-any coercions unless necessary) - ToNever, - /// Don't fallback at all - NoFallback, -} - -#[derive(Copy, Clone, PartialEq, Debug, PrintAttribute, Default)] -#[derive(StableHash, Encodable, Decodable)] -pub enum DivergingBlockBehavior { - /// This is the current stable behavior: - /// - /// ```rust - /// { - /// return; - /// } // block has type = !, even though we are supposedly dropping it with `;` - /// ``` - #[default] - Never, - - /// Alternative behavior: - /// - /// ```ignore (very-unstable-new-attribute) - /// #![rustc_never_type_options(diverging_block_default = "unit")] - /// { - /// return; - /// } // block has type = (), since we are dropping `!` from `return` with `;` - /// ``` - Unit, -} - #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, StableHash, PrintAttribute)] pub enum InlineAttr { None, @@ -1367,12 +1331,6 @@ pub enum AttributeKind { /// Represents `#[rustc_never_returns_null_ptr]` RustcNeverReturnsNullPtr, - /// Represents `#[rustc_never_type_options]`. - RustcNeverTypeOptions { - fallback: Option, - diverging_block_default: Option, - }, - /// Represents `#[rustc_no_implicit_autorefs]` RustcNoImplicitAutorefs, diff --git a/compiler/rustc_attr_ir/src/encode_cross_crate.rs b/compiler/rustc_attr_ir/src/encode_cross_crate.rs index 164ab3c5822d0..50ad6fc18f4ef 100644 --- a/compiler/rustc_attr_ir/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_ir/src/encode_cross_crate.rs @@ -165,7 +165,6 @@ impl AttributeKind { RustcMustImplementOneOf { .. } => No, RustcMustMatchExhaustively(..) => Yes, RustcNeverReturnsNullPtr => Yes, - RustcNeverTypeOptions { .. } => No, RustcNoImplicitAutorefs => Yes, RustcNoImplicitBounds => No, RustcNoMirInline => Yes, diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 3620847a19301..0df3d9a626bee 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -4,8 +4,8 @@ use rustc_ast::{LitIntType, LitKind, MetaItemLit}; use rustc_attr_ir::lang_items::LangItem; use rustc_attr_ir::target::GenericParamKind; use rustc_attr_ir::{ - BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior, - DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcMirKind, + BorrowckGraphvizFormatKind, CguFields, CguKind, RustcCleanAttribute, RustcCleanQueries, + RustcMirKind, }; use rustc_data_structures::fx::FxHashMap; use rustc_feature::AttributeStability; @@ -397,79 +397,6 @@ impl NoArgsAttributeParser for RustcCaptureAnalysisParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCaptureAnalysis; } -pub(crate) struct RustcNeverTypeOptionsParser; - -impl SingleAttributeParser for RustcNeverTypeOptionsParser { - const PATH: &[Symbol] = &[sym::rustc_never_type_options]; - const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); - const TEMPLATE: AttributeTemplate = template!(List: &[ - r#"fallback = "unit", "never", "no""#, - r#"diverging_block_default = "unit", "never""#, - ]); - const STABILITY: AttributeStability = unstable!( - rustc_attrs, - "`rustc_never_type_options` is used to experiment with never type fallback and work on never type stabilization" - ); - - fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { - let list = cx.expect_list(args, cx.attr_span)?; - - let mut fallback = None::; - let mut diverging_block_default = None::; - - for arg in list.mixed() { - let Some((ident, arg)) = cx.expect_name_value(arg, arg.span(), None) else { - continue; - }; - - let res = match ident.name { - sym::fallback => &mut fallback, - sym::diverging_block_default => &mut diverging_block_default, - _ => { - cx.adcx().expected_specific_argument( - ident.span, - &[sym::fallback, sym::diverging_block_default], - ); - continue; - } - }; - - let field = cx.expect_string_literal(arg)?; - - if res.is_some() { - cx.adcx().duplicate_key(ident.span, ident.name); - continue; - } - - *res = Some(Ident { name: field, span: arg.value_span }); - } - - let fallback = match fallback { - None => None, - Some(Ident { name: sym::unit, .. }) => Some(DivergingFallbackBehavior::ToUnit), - Some(Ident { name: sym::never, .. }) => Some(DivergingFallbackBehavior::ToNever), - Some(Ident { name: sym::no, .. }) => Some(DivergingFallbackBehavior::NoFallback), - Some(Ident { span, .. }) => { - cx.adcx() - .expected_specific_argument_strings(span, &[sym::unit, sym::never, sym::no]); - return None; - } - }; - - let diverging_block_default = match diverging_block_default { - None => None, - Some(Ident { name: sym::unit, .. }) => Some(DivergingBlockBehavior::Unit), - Some(Ident { name: sym::never, .. }) => Some(DivergingBlockBehavior::Never), - Some(Ident { span, .. }) => { - cx.adcx().expected_specific_argument_strings(span, &[sym::unit, sym::no]); - return None; - } - }; - - Some(AttributeKind::RustcNeverTypeOptions { fallback, diverging_block_default }) - } -} - pub(crate) struct RustcTrivialFieldReadsParser; impl NoArgsAttributeParser for RustcTrivialFieldReadsParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 7fe799a027c54..dfda3dc722e1b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -246,7 +246,6 @@ attribute_parsers!( Single, Single, Single, - Single, Single, Single, Single, diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 889b8e841febc..8dd38d2eaa407 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -4,7 +4,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph; use rustc_data_structures::graph::vec_graph::VecGraph; use rustc_data_structures::unord::{UnordMap, UnordSet}; -use rustc_hir::attrs::DivergingFallbackBehavior; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{InferKind, Visitor}; @@ -14,7 +13,7 @@ use rustc_lint_defs::builtin::{ }; use rustc_middle::ty::{self, FloatVid, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_span::def_id::LocalDefId; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_trait_selection::traits::TraitEngine; use tracing::debug; @@ -72,77 +71,63 @@ impl<'tcx> FnCtxt<'_, 'tcx> { return false; } - let (diverging_fallback, diverging_fallback_ty) = self.calculate_diverging_fallback(); + // If tainted by errors, fallback all unresolved variables to error type, + // in order to prevent unnecessary diagnostics. + if let Some(guar) = self.tainted_by_errors() { + self.fallback_types_to_error(guar, unresolved_ty, unresolved_int, unresolved_float); + return true; + } + + let diverging_fallback = self.calculate_diverging_fallback(); let fallback_to_f32 = self.calculate_fallback_to_f32(&unresolved_float); - // We do fallback in two passes, to try to generate - // better error messages. - // The first time, we do *not* replace opaque types. - let mut fallback_occurred = false; - - for vid in unresolved_ty { - fallback_occurred |= self.fallback_if_possible( - vid, - || { - diverging_fallback.contains(&vid).then(|| { - self.diverging_fallback_has_occurred.set(true); - diverging_fallback_ty - }) - }, - |vid| (Ty::new_var(self.tcx, vid), self.type_var_origin(vid).span), - ); + // All unresolved int and float variables always use fallback, + // whereas unresolved type variables might not use fallback. + let mut fallback_occurred = !unresolved_int.is_empty() || !unresolved_float.is_empty(); + + for &vid in unresolved_ty.iter().filter(|&vid| diverging_fallback.contains(vid)) { + let span = self.type_var_origin(vid).span; + self.demand_eqtype(span, Ty::new_var(self.tcx, vid), self.tcx.types.never); + + self.diverging_fallback_has_occurred.set(true); + fallback_occurred = true; } for vid in unresolved_int { - fallback_occurred |= self.fallback_if_possible( - vid, - || Some(self.tcx.types.i32), - // Int variables have no origin?.. - |vid| (Ty::new_int_var(self.tcx, vid), DUMMY_SP), - ); + self.demand_eqtype(DUMMY_SP, Ty::new_int_var(self.tcx, vid), self.tcx.types.i32); } for vid in unresolved_float { - fallback_occurred |= self.fallback_if_possible( - vid, - || { - Some(if fallback_to_f32.contains(&vid) { - self.tcx.types.f32 - } else { - self.tcx.types.f64 - }) - }, - |vid| (Ty::new_float_var(self.tcx, vid), self.float_var_origin(vid).span), - ); + let fallback = if fallback_to_f32.contains(&vid) { + self.tcx.types.f32 + } else { + self.tcx.types.f64 + }; + let span = self.float_var_origin(vid).span; + self.demand_eqtype(span, Ty::new_float_var(self.tcx, vid), fallback); } fallback_occurred } - /// Applies fallback to `vid`, if possible. - /// - /// - If `self.tainted_by_errors()` unifies the type represented by `vid` with error - /// - Otherwise, if `fallback` returns `Some`, unifies it with the output of `fallback` - /// - Otherwise, does nothing - /// - /// Returns whatever fallback has been applied. - fn fallback_if_possible( + fn fallback_types_to_error( &self, - vid: V, - fallback: impl FnOnce() -> Option>, - vid_to_ty_and_span: impl FnOnce(V) -> (Ty<'tcx>, Span), - ) -> bool { - let fallback = if let Some(e) = self.tainted_by_errors() { - Ty::new_error(self.tcx, e) - } else if let Some(fallback) = fallback() { - fallback - } else { - return false; - }; + guar: ErrorGuaranteed, + unresolved_ty: Vec, + unresolved_int: Vec, + unresolved_float: Vec, + ) { + let vars = unresolved_ty + .into_iter() + .map(|vid| Ty::new_var(self.tcx, vid)) + .chain(unresolved_int.into_iter().map(|vid| Ty::new_int_var(self.tcx, vid))) + .chain(unresolved_float.into_iter().map(|vid| Ty::new_float_var(self.tcx, vid))); - let (ty, span) = vid_to_ty_and_span(vid); - self.demand_eqtype(span, ty, fallback); - true + let error = Ty::new_error(self.tcx, guar); + + for var in vars { + self.demand_eqtype(DUMMY_SP, var, error); + } } /// Existing code relies on `f32: From` (usually written as `T: Into`) resolving `T` to @@ -209,34 +194,25 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fallback_to_f32 } - fn calculate_diverging_fallback(&self) -> (UnordSet, Ty<'tcx>) { - let diverging_fallback_ty = match self.diverging_fallback_behavior { - DivergingFallbackBehavior::ToUnit => self.tcx.types.unit, - DivergingFallbackBehavior::ToNever => self.tcx.types.never, - DivergingFallbackBehavior::NoFallback => { - // the type doesn't matter, since no fallback will occur - return (UnordSet::new(), self.tcx.types.unit); - } - }; - + fn calculate_diverging_fallback(&self) -> UnordSet { // Compute the diverging root vids D -- that is, the root vid of // those type variables that (a) are the target of a coercion from // a `!` type and (b) have not yet been solved. // - // These variables are the ones that are targets for fallback to - // either `!` or `()`. + // These variables are the ones that are targets for fallback to `!`. let diverging_root_vids: Vec = self .diverging_type_vars .borrow() .iter() .filter_map(|&vid| self.infcx.shallow_resolve_ty_var_or_get_root(vid).err()) .collect(); - { - // Construct a coercion graph where an edge `A -> B` indicates - // a type variable is that is coerced - let coercion_graph = self.create_coercion_graph(); + { if !diverging_root_vids.is_empty() { + // Construct a coercion graph where an edge `A -> B` indicates + // a type variable is that is coerced + let coercion_graph = self.create_coercion_graph(); + let unsafe_infer_vars = compute_unsafe_infer_vars(self, self.body_def_id); for &root_vid in &diverging_root_vids { @@ -249,9 +225,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } } - let diverging_fallback = diverging_root_vids.into_iter().collect::>(); - - (diverging_fallback, diverging_fallback_ty) + diverging_root_vids.into_iter().collect::>() } fn lint_never_type_fallback_flowing_into_unsafe_code( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9becad0db1ca2..ba44d1966d971 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -8,7 +8,6 @@ use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, listify, pluralize}; use rustc_hir as hir; -use rustc_hir::attrs::DivergingBlockBehavior; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -1357,9 +1356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // #41425 -- label the implicit `()` as being the // "found type" here, rather than the "expected type". - if !self.diverges.get().is_always() - || matches!(self.diverging_block_behavior, DivergingBlockBehavior::Unit) - { + if !self.diverges.get().is_always() { // #50009 -- Do not point at the entire fn block span, point at the return type // span, as it is the cause of the requirement, and // `consider_hint_about_removing_semicolon` will point at the last expression diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 06c8583b632ae..0c175e747c63b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -11,9 +11,8 @@ use std::ops::Deref; pub(crate) use inspect_obligations::UseSubtyping; use rustc_data_structures::thin_vec::{ThinVec, thin_vec}; use rustc_errors::DiagCtxtHandle; -use rustc_hir::attrs::{DivergingBlockBehavior, DivergingFallbackBehavior}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, HirId, ItemLocalMap, find_attr}; +use rustc_hir::{self as hir, HirId, ItemLocalMap}; use rustc_hir_analysis::hir_ty_lowering::{ HirTyLowerer, InherentAssocCandidate, RegionInferReason, }; @@ -121,9 +120,6 @@ pub(crate) struct FnCtxt<'a, 'tcx> { /// of never type fallback. This is only used for diagnostics. pub(super) diverging_fallback_has_occurred: Cell, - pub(super) diverging_fallback_behavior: DivergingFallbackBehavior, - pub(super) diverging_block_behavior: DivergingBlockBehavior, - /// Clauses that we lowered as part of the `impl_trait_in_bindings` feature. /// /// These are stored here so we may collect them when canonicalizing user @@ -141,8 +137,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_def_id: LocalDefId, ) -> FnCtxt<'a, 'tcx> { - let (diverging_fallback_behavior, diverging_block_behavior) = - never_type_behavior(root_ctxt.tcx); FnCtxt { body_def_id, param_env, @@ -158,8 +152,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }), root_ctxt, diverging_fallback_has_occurred: Cell::new(false), - diverging_fallback_behavior, - diverging_block_behavior, trait_ascriptions: Default::default(), has_rustc_attrs: root_ctxt.tcx.features().rustc_attrs(), } @@ -491,21 +483,3 @@ impl<'tcx> LoweredTy<'tcx> { LoweredTy { raw, normalized } } } - -fn never_type_behavior(tcx: TyCtxt<'_>) -> (DivergingFallbackBehavior, DivergingBlockBehavior) { - // FIXME(waffle): rip out the whole system which allows you to choose never type fallback - let (fallback, block) = parse_never_type_options_attr(tcx); - let fallback = fallback.unwrap_or_else(|| DivergingFallbackBehavior::ToNever); - let block = block.unwrap_or_default(); - - (fallback, block) -} - -fn parse_never_type_options_attr( - tcx: TyCtxt<'_>, -) -> (Option, Option) { - // Error handling is dubious here (unwraps), but that's probably fine for an internal attribute. - // Just don't write incorrect attributes <3 - - find_attr!(tcx, crate, RustcNeverTypeOptions {fallback, diverging_block_default} => (*fallback, *diverging_block_default)).unwrap_or_default() -} diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2f69823d54afd..c3d19542c1645 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -372,7 +372,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcMir(_) => (), AttributeKind::RustcMustMatchExhaustively(..) => (), AttributeKind::RustcNeverReturnsNullPtr => (), - AttributeKind::RustcNeverTypeOptions { .. } => (), AttributeKind::RustcNoImplicitAutorefs => (), AttributeKind::RustcNoImplicitBounds => (), AttributeKind::RustcNoMirInline => (), diff --git a/tests/ui/attributes/malformed-never-type-options.rs b/tests/ui/attributes/malformed-never-type-options.rs deleted file mode 100644 index 7dd7a854ed2e3..0000000000000 --- a/tests/ui/attributes/malformed-never-type-options.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Regression test for #124352 -//! The `rustc_*` attribute is malformed, but ICEing without a `feature(rustc_attrs)` is still bad. - -#![rustc_never_type_options(: Unsize = "hi")] -//~^ ERROR expected a literal -//~| ERROR use of an internal attribute - -fn main() {} diff --git a/tests/ui/attributes/malformed-never-type-options.stderr b/tests/ui/attributes/malformed-never-type-options.stderr deleted file mode 100644 index 0bf7f5cdf093b..0000000000000 --- a/tests/ui/attributes/malformed-never-type-options.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0658]: use of an internal attribute - --> $DIR/malformed-never-type-options.rs:4:4 - | -LL | #![rustc_never_type_options(: Unsize = "hi")] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: the `rustc_never_type_options` attribute is an internal implementation detail that will never be stable - = note: `rustc_never_type_options` is used to experiment with never type fallback and work on never type stabilization - -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `:` - --> $DIR/malformed-never-type-options.rs:4:29 - | -LL | #![rustc_never_type_options(: Unsize = "hi")] - | ^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/never_type/fallback_change/from_infer_breaking_with_unit_fallback.rs b/tests/ui/never_type/fallback_change/from_infer_breaking_with_unit_fallback.rs index a13e52966973d..9705dcbc56aed 100644 --- a/tests/ui/never_type/fallback_change/from_infer_breaking_with_unit_fallback.rs +++ b/tests/ui/never_type/fallback_change/from_infer_breaking_with_unit_fallback.rs @@ -4,12 +4,7 @@ // Note that the original version with the `?` does not fail anymore even with fallback to unit, // see `tests/ui/never_type/fallback_change/question_mark_from_never.rs`. // -//@ revisions: unit never -//@[never] check-pass -#![allow(internal_features)] -#![feature(rustc_attrs)] -#![cfg_attr(unit, rustc_never_type_options(fallback = "unit"))] -#![cfg_attr(never, rustc_never_type_options(fallback = "never"))] +//@ check-pass struct E; @@ -23,7 +18,6 @@ impl From for E { fn foo(never: !) { >::from(never); // Ok >::from(never); // Should the inference fail? - //[unit]~^ error: the trait bound `E: From<()>` is not satisfied } fn main() {} diff --git a/tests/ui/never_type/fallback_change/from_infer_breaking_with_unit_fallback.unit.stderr b/tests/ui/never_type/fallback_change/from_infer_breaking_with_unit_fallback.unit.stderr deleted file mode 100644 index da44d72d2cffb..0000000000000 --- a/tests/ui/never_type/fallback_change/from_infer_breaking_with_unit_fallback.unit.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0277]: the trait bound `E: From<()>` is not satisfied - --> $DIR/from_infer_breaking_with_unit_fallback.rs:25:6 - | -LL | >::from(never); // Should the inference fail? - | ^ unsatisfied trait bound - | -help: the trait `From<()>` is not implemented for `E` - but trait `From` is implemented for it - --> $DIR/from_infer_breaking_with_unit_fallback.rs:16:1 - | -LL | impl From for E { - | ^^^^^^^^^^^^^^^^^^ - = help: for that trait implementation, expected `!`, found `()` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/fallback_change/question_mark_from_never.rs b/tests/ui/never_type/fallback_change/question_mark_from_never.rs index 1685b66b538ee..b896883056ea8 100644 --- a/tests/ui/never_type/fallback_change/question_mark_from_never.rs +++ b/tests/ui/never_type/fallback_change/question_mark_from_never.rs @@ -2,12 +2,7 @@ // // See also: `tests/ui/never_type/fallback_change/from_infer_breaking_with_unit_fallback.rs`. // -//@ revisions: unit never //@ check-pass -#![allow(internal_features)] -#![feature(rustc_attrs)] -#![cfg_attr(unit, rustc_never_type_options(fallback = "unit"))] -#![cfg_attr(never, rustc_never_type_options(fallback = "never"))] type Infallible = !;