Rollup merge of #136429 - fmease:gci-fix-def-site-checks, r=BoxyUwU

GCI: At their def site, actually wfcheck the where-clause & always eval free lifetime-generic constants

* 1st commit: Partially addresses [#136204](https://github.com/rust-lang/rust/issues/136204) by turning const eval errors from post to pre-mono for free lifetime-generic constants.
  * As the linked issue/comment states, on master there's a difference between `const _: () = panic!();` (pre-mono error) and `const _<'a>: () = panic!();` (post-mono error) which feels wrong.
  * With this PR, both become pre-mono ones!
* 2nd commit: Oof, yeah, I missed that in the initial impl!

This doesn't fully address #136204 because I still haven't figured out how & where to properly & best suppress const eval of free constants whose predicates don't hold at the def site. The motivating example is `const _UNUSED: () = () where for<'_delay> String: Copy;` which can also be found over at the tracking issue #113521.

r? compiler-errors or reassign
This commit is contained in:
Jacob Pratt
2025-05-29 04:49:39 +02:00
committed by GitHub
8 changed files with 64 additions and 38 deletions

View File

@@ -298,11 +298,9 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
check_item_fn(tcx, def_id, ident, item.span, sig.decl)
}
hir::ItemKind::Static(_, ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
}
hir::ItemKind::Const(_, ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
check_static_item(tcx, def_id, ty.span, UnsizedHandling::Forbid)
}
hir::ItemKind::Const(_, ty, ..) => check_const_item(tcx, def_id, ty.span, item.span),
hir::ItemKind::Struct(_, _, hir_generics) => {
let res = check_type_defn(tcx, item, false);
check_variances_for_type_defn(tcx, item, hir_generics);
@@ -366,7 +364,7 @@ fn check_foreign_item<'tcx>(
check_item_fn(tcx, def_id, item.ident, item.span, sig.decl)
}
hir::ForeignItemKind::Static(ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail)
check_static_item(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail)
}
hir::ForeignItemKind::Type => Ok(()),
}
@@ -1331,14 +1329,13 @@ enum UnsizedHandling {
AllowIfForeignTail,
}
fn check_item_type(
#[instrument(level = "debug", skip(tcx, ty_span, unsized_handling))]
fn check_static_item(
tcx: TyCtxt<'_>,
item_id: LocalDefId,
ty_span: Span,
unsized_handling: UnsizedHandling,
) -> Result<(), ErrorGuaranteed> {
debug!("check_item_type: {:?}", item_id);
enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| {
let ty = tcx.type_of(item_id).instantiate_identity();
let item_ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty);
@@ -1388,6 +1385,34 @@ fn check_item_type(
})
}
fn check_const_item(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
ty_span: Span,
item_span: Span,
) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, ty_span, def_id, |wfcx| {
let ty = tcx.type_of(def_id).instantiate_identity();
let ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(def_id)), ty);
wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(def_id)), ty.into());
wfcx.register_bound(
traits::ObligationCause::new(
ty_span,
wfcx.body_def_id,
ObligationCauseCode::SizedConstOrStatic,
),
wfcx.param_env,
ty,
tcx.require_lang_item(LangItem::Sized, None),
);
check_where_clauses(wfcx, item_span, def_id);
Ok(())
})
}
#[instrument(level = "debug", skip(tcx, hir_self_ty, hir_trait_ref))]
fn check_impl<'tcx>(
tcx: TyCtxt<'tcx>,

View File

@@ -203,7 +203,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
tcx.ensure_ok().eval_static_initializer(item_def_id);
check::maybe_check_static_with_link_section(tcx, item_def_id);
}
DefKind::Const if tcx.generics_of(item_def_id).is_empty() => {
DefKind::Const if !tcx.generics_of(item_def_id).own_requires_monomorphization() => {
// FIXME(generic_const_items): Passing empty instead of identity args is fishy but
// seems to be fine for now. Revisit this!
let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty());
let cid = GlobalId { instance, promoted: None };
let typing_env = ty::TypingEnv::fully_monomorphized();

View File

@@ -9,7 +9,6 @@ use super::{
ReportedErrorInfo,
};
use crate::mir;
use crate::query::TyCtxtEnsureOk;
use crate::ty::{self, GenericArgs, TyCtxt, TypeVisitableExt};
impl<'tcx> TyCtxt<'tcx> {
@@ -197,24 +196,3 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
}
impl<'tcx> TyCtxtEnsureOk<'tcx> {
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_poly(self, def_id: DefId) {
// In some situations def_id will have generic parameters within scope, but they aren't allowed
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
// into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are
// encountered.
let args = GenericArgs::identity_for_item(self.tcx, def_id);
let instance = ty::Instance::new_raw(def_id, self.tcx.erase_regions(args));
let cid = GlobalId { instance, promoted: None };
let typing_env = ty::TypingEnv::post_analysis(self.tcx, def_id);
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs = self.tcx.erase_regions(typing_env.as_query_input(cid));
self.eval_to_const_value_raw(inputs)
}
}

View File

@@ -1483,7 +1483,7 @@ impl<'v> RootCollector<'_, 'v> {
// But even just declaring them must collect the items they refer to
// unless their generics require monomorphization.
if !self.tcx.generics_of(id.owner_id).requires_monomorphization(self.tcx)
if !self.tcx.generics_of(id.owner_id).own_requires_monomorphization()
&& let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id())
{
collect_const_value(self.tcx, val, self.output);

View File

@@ -1,5 +1,5 @@
error[E0080]: evaluation of `_::<'_>` failed
--> $DIR/def-site-eval.rs:14:20
error[E0080]: evaluation of constant value failed
--> $DIR/def-site-eval.rs:13:20
|
LL | const _<'_a>: () = panic!();
| ^^^^^^^^ evaluation panicked: explicit panic

View File

@@ -1,16 +1,15 @@
//! Test that we only evaluate free const items (their def site to be clear)
//! whose generics don't require monomorphization.
#![feature(generic_const_items)]
#![allow(incomplete_features)]
#![expect(incomplete_features)]
//@ revisions: fail pass
//@[fail] build-fail (we require monomorphization)
//@[pass] build-pass (we require monomorphization)
//@[pass] check-pass
const _<_T>: () = panic!();
const _<const _N: usize>: () = panic!();
#[cfg(fail)]
const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation of `_::<'_>` failed
const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation of constant value failed
fn main() {}

View File

@@ -0,0 +1,9 @@
//! Ensure that we check the predicates for well-formedness at the definition site.
#![feature(generic_const_items)]
#![expect(incomplete_features)]
const _: () = ()
where
Vec<str>: Sized; //~ ERROR the size for values of type `str` cannot be known at compilation time
fn main() {}

View File

@@ -0,0 +1,13 @@
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/def-site-predicates-wf.rs:7:15
|
LL | Vec<str>: Sized;
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `str`
note: required by an implicit `Sized` bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.