diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 2b33da3c49a07..5f081b6fb91ca 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1104,6 +1104,23 @@ fn check_type_defn<'tcx>( for variant in variants.iter() { // All field types must be well-formed. for field in &variant.fields { + if let Some(def_id) = field.value + && let Some(_ty) = tcx.type_of(def_id).no_bound_vars() + { + if let Some(def_id) = def_id.as_local() + && let hir::Node::AnonConst(anon) = tcx.hir_node_by_def_id(def_id) + && let expr = &tcx.hir().body(anon.body).value + && let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let Res::Def(DefKind::ConstParam, _def_id) = path.res + { + // Do not evaluate bare `const` params, as those would ICE and are only + // usable if `#![feature(generic_const_exprs)]` is enabled. + } else { + // Evaluate the constant proactively, to emit an error if the constant has + // an unconditional error. We only do so if the const has no type params. + let _ = tcx.const_eval_poly(def_id.into()); + } + } let field_id = field.did.expect_local(); let hir::FieldDef { ty: hir_ty, .. } = tcx.hir_node_by_def_id(field_id).expect_field(); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7c5e8848958d7..40ffed480381a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -211,10 +211,6 @@ lint_dangling_pointers_from_temporaries = a dangling pointer will be produced be .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned .help = for more information, see -lint_default_field_always_invalid_const = default field fails const-evaluation - .label = this field's constant fails const-evaluation, as seen in the previous error - .help = you can skip const-evaluation of default fields by enabling this lint - lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary diff --git a/compiler/rustc_lint/src/default_field_always_invalid.rs b/compiler/rustc_lint/src/default_field_always_invalid.rs deleted file mode 100644 index 46cffb53b4b63..0000000000000 --- a/compiler/rustc_lint/src/default_field_always_invalid.rs +++ /dev/null @@ -1,91 +0,0 @@ -use rustc_hir as hir; -use rustc_middle::lint::LintLevelSource; -use rustc_middle::mir::interpret::ErrorHandled; -use rustc_session::lint::Level; -use rustc_session::{declare_lint, declare_lint_pass}; - -use crate::lints::DefaultFieldAlwaysInvalidConst; -use crate::{LateContext, LateLintPass}; - -declare_lint! { - /// The `default_field_always_invalid_const` lint checks for structs with - /// default fields const values that will *always* fail to be created. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![feature(default_field_values)] - /// #[deny(default_field_always_invalid_const)] - /// struct Foo { - /// bar: u8 = 130 + 130, // `260` doesn't fit in `u8` - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Without this lint, the error would only happen only during construction - /// of the affected type. For example, given the type above, `Foo { .. }` - /// would always fail to build, but `Foo { bar: 0 }` would be accepted. This - /// lint will catch accidental cases of const values that would fail to - /// compile, but won't detect cases that are only partially evaluated. - pub DEFAULT_FIELD_ALWAYS_INVALID_CONST, - Deny, - "using this default field will always fail to compile" -} - -declare_lint_pass!(DefaultFieldAlwaysInvalid => [DEFAULT_FIELD_ALWAYS_INVALID_CONST]); - -impl<'tcx> LateLintPass<'tcx> for DefaultFieldAlwaysInvalid { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - let data = match item.kind { - hir::ItemKind::Struct(data, _generics) => data, - _ => return, - }; - let hir::VariantData::Struct { fields, recovered: _ } = data else { - return; - }; - - let (level, source) = - cx.tcx.lint_level_at_node(DEFAULT_FIELD_ALWAYS_INVALID_CONST, item.hir_id()); - match level { - Level::Deny | Level::Forbid => {} - Level::Warn | Level::ForceWarn(_) | Level::Expect(_) => { - // We *can't* turn the const eval error into a warning, so we make it a - // warning to not use `#[warn(default_field_always_invalid_const)]`. - let invalid_msg = "lint `default_field_always_invalid_const` can't be warned on"; - #[allow(rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic)] - if let LintLevelSource::Node { span, .. } = source { - let mut err = cx.tcx.sess.dcx().struct_span_warn(span, invalid_msg); - err.span_label( - span, - "either `deny` or `allow`, no other lint level is supported for this lint", - ); - err.emit(); - } else { - cx.tcx.sess.dcx().warn(invalid_msg); - } - } - Level::Allow => { - // We don't even look at the fields. - return; - } - } - for field in fields { - if let Some(c) = field.default - && let Some(_ty) = cx.tcx.type_of(c.def_id).no_bound_vars() - && let Err(ErrorHandled::Reported(_, _)) = cx.tcx.const_eval_poly(c.def_id.into()) - { - // We use the item's hir id because the const's hir id might resolve inside of a - // foreign macro, meaning the lint won't trigger. - cx.tcx.emit_node_span_lint( - DEFAULT_FIELD_ALWAYS_INVALID_CONST, - item.hir_id(), - field.span, - DefaultFieldAlwaysInvalidConst { span: field.span, help: () }, - ); - } - } - } -} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index baf2703511e2e..a99c94592b302 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -41,7 +41,6 @@ mod async_fn_in_trait; pub mod builtin; mod context; mod dangling; -mod default_field_always_invalid; mod deref_into_dyn_supertrait; mod drop_forget_useless; mod early; @@ -86,7 +85,6 @@ use async_closures::AsyncClosureUsage; use async_fn_in_trait::AsyncFnInTrait; use builtin::*; use dangling::*; -use default_field_always_invalid::*; use deref_into_dyn_supertrait::*; use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; @@ -195,7 +193,6 @@ late_lint_methods!( DropForgetUseless: DropForgetUseless, ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDefinitions: ImproperCTypesDefinitions, - DefaultFieldAlwaysInvalid: DefaultFieldAlwaysInvalid, InvalidFromUtf8: InvalidFromUtf8, VariantSizeDifferences: VariantSizeDifferences, PathStatements: PathStatements, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 7b411008ed5b6..e6eae7e736832 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -730,15 +730,6 @@ pub(crate) struct UndroppedManuallyDropsSuggestion { pub end_span: Span, } -#[derive(LintDiagnostic)] -#[diag(lint_default_field_always_invalid_const)] -pub(crate) struct DefaultFieldAlwaysInvalidConst { - #[label] - pub span: Span, - #[help] - pub help: (), -} - // invalid_from_utf8.rs #[derive(LintDiagnostic)] pub(crate) enum InvalidFromUtf8Diag { diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr index e60ec392fdd6d..5b9d2df5a5d73 100644 --- a/tests/ui/structs/default-field-values-failures.stderr +++ b/tests/ui/structs/default-field-values-failures.stderr @@ -21,6 +21,12 @@ error: default fields are not supported in tuple structs LL | pub struct Rak(i32 = 42); | ^^ default fields are only supported on structs +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/default-field-values-failures.rs:20:14 + | +LL | bar: S = Self::S, + | ^^^^ + error[E0277]: the trait bound `S: Default` is not satisfied --> $DIR/default-field-values-failures.rs:14:5 | @@ -106,12 +112,6 @@ LL - let _ = Rak(.., 0); LL + let _ = Rak(0); | -error: generic `Self` types are currently not permitted in anonymous constants - --> $DIR/default-field-values-failures.rs:20:14 - | -LL | bar: S = Self::S, - | ^^^^ - error: aborting due to 9 previous errors Some errors have detailed explanations: E0061, E0277, E0308. diff --git a/tests/ui/structs/default-field-values-invalid-const.rs b/tests/ui/structs/default-field-values-invalid-const.rs index 6838238064be5..203a712868b7e 100644 --- a/tests/ui/structs/default-field-values-invalid-const.rs +++ b/tests/ui/structs/default-field-values-invalid-const.rs @@ -1,18 +1,15 @@ #![feature(default_field_values, generic_const_exprs)] #![allow(incomplete_features)] -#[warn(default_field_always_invalid_const)] //~ WARN lint `default_field_always_invalid_const` can't be warned on pub struct Bat { pub bax: u8 = panic!("asdf"), //~^ ERROR evaluation of constant value failed - //~| WARN default field fails const-evaluation } pub struct Baz { pub bax: u8 = 130 + C, // ok pub bat: u8 = 130 + 130, //~^ ERROR evaluation of `Baz::::bat::{constant#0}` failed - //~| ERROR default field fails const-evaluation pub bay: u8 = 1, // ok } diff --git a/tests/ui/structs/default-field-values-invalid-const.stderr b/tests/ui/structs/default-field-values-invalid-const.stderr index a0d84271f4bc9..47f25a1f38e3f 100644 --- a/tests/ui/structs/default-field-values-invalid-const.stderr +++ b/tests/ui/structs/default-field-values-invalid-const.stderr @@ -1,45 +1,17 @@ -warning: lint `default_field_always_invalid_const` can't be warned on - --> $DIR/default-field-values-invalid-const.rs:4:8 - | -LL | #[warn(default_field_always_invalid_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ either `deny` or `allow`, no other lint level is supported for this lint - error[E0080]: evaluation of constant value failed - --> $DIR/default-field-values-invalid-const.rs:6:19 + --> $DIR/default-field-values-invalid-const.rs:5:19 | LL | pub bax: u8 = panic!("asdf"), - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'asdf', $DIR/default-field-values-invalid-const.rs:6:19 + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'asdf', $DIR/default-field-values-invalid-const.rs:5:19 | = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: default field fails const-evaluation - --> $DIR/default-field-values-invalid-const.rs:6:5 - | -LL | pub bax: u8 = panic!("asdf"), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this field's constant fails const-evaluation, as seen in the previous error - | - = help: you can skip const-evaluation of default fields by enabling this lint -note: the lint level is defined here - --> $DIR/default-field-values-invalid-const.rs:4:8 - | -LL | #[warn(default_field_always_invalid_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0080]: evaluation of `Baz::::bat::{constant#0}` failed - --> $DIR/default-field-values-invalid-const.rs:13:19 + --> $DIR/default-field-values-invalid-const.rs:11:19 | LL | pub bat: u8 = 130 + 130, | ^^^^^^^^^ attempt to compute `130_u8 + 130_u8`, which would overflow -error: default field fails const-evaluation - --> $DIR/default-field-values-invalid-const.rs:13:5 - | -LL | pub bat: u8 = 130 + 130, - | ^^^^^^^^^^^^^^^^^^^^^^^ this field's constant fails const-evaluation, as seen in the previous error - | - = help: you can skip const-evaluation of default fields by enabling this lint - = note: `#[deny(default_field_always_invalid_const)]` on by default - -error: aborting due to 3 previous errors; 2 warnings emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`.