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:
@@ -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)
|
check_item_fn(tcx, def_id, ident, item.span, sig.decl)
|
||||||
}
|
}
|
||||||
hir::ItemKind::Static(_, ty, ..) => {
|
hir::ItemKind::Static(_, 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_item_type(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) => {
|
hir::ItemKind::Struct(_, _, hir_generics) => {
|
||||||
let res = check_type_defn(tcx, item, false);
|
let res = check_type_defn(tcx, item, false);
|
||||||
check_variances_for_type_defn(tcx, item, hir_generics);
|
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)
|
check_item_fn(tcx, def_id, item.ident, item.span, sig.decl)
|
||||||
}
|
}
|
||||||
hir::ForeignItemKind::Static(ty, ..) => {
|
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(()),
|
hir::ForeignItemKind::Type => Ok(()),
|
||||||
}
|
}
|
||||||
@@ -1331,14 +1329,13 @@ enum UnsizedHandling {
|
|||||||
AllowIfForeignTail,
|
AllowIfForeignTail,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_item_type(
|
#[instrument(level = "debug", skip(tcx, ty_span, unsized_handling))]
|
||||||
|
fn check_static_item(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
item_id: LocalDefId,
|
item_id: LocalDefId,
|
||||||
ty_span: Span,
|
ty_span: Span,
|
||||||
unsized_handling: UnsizedHandling,
|
unsized_handling: UnsizedHandling,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
debug!("check_item_type: {:?}", item_id);
|
|
||||||
|
|
||||||
enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| {
|
enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| {
|
||||||
let ty = tcx.type_of(item_id).instantiate_identity();
|
let ty = tcx.type_of(item_id).instantiate_identity();
|
||||||
let item_ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty);
|
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))]
|
#[instrument(level = "debug", skip(tcx, hir_self_ty, hir_trait_ref))]
|
||||||
fn check_impl<'tcx>(
|
fn check_impl<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
|||||||
@@ -203,7 +203,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||||||
tcx.ensure_ok().eval_static_initializer(item_def_id);
|
tcx.ensure_ok().eval_static_initializer(item_def_id);
|
||||||
check::maybe_check_static_with_link_section(tcx, 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 instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty());
|
||||||
let cid = GlobalId { instance, promoted: None };
|
let cid = GlobalId { instance, promoted: None };
|
||||||
let typing_env = ty::TypingEnv::fully_monomorphized();
|
let typing_env = ty::TypingEnv::fully_monomorphized();
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ use super::{
|
|||||||
ReportedErrorInfo,
|
ReportedErrorInfo,
|
||||||
};
|
};
|
||||||
use crate::mir;
|
use crate::mir;
|
||||||
use crate::query::TyCtxtEnsureOk;
|
|
||||||
use crate::ty::{self, GenericArgs, TyCtxt, TypeVisitableExt};
|
use crate::ty::{self, GenericArgs, TyCtxt, TypeVisitableExt};
|
||||||
|
|
||||||
impl<'tcx> TyCtxt<'tcx> {
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1483,7 +1483,7 @@ impl<'v> RootCollector<'_, 'v> {
|
|||||||
|
|
||||||
// But even just declaring them must collect the items they refer to
|
// But even just declaring them must collect the items they refer to
|
||||||
// unless their generics require monomorphization.
|
// 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())
|
&& let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id())
|
||||||
{
|
{
|
||||||
collect_const_value(self.tcx, val, self.output);
|
collect_const_value(self.tcx, val, self.output);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
error[E0080]: evaluation of `_::<'_>` failed
|
error[E0080]: evaluation of constant value failed
|
||||||
--> $DIR/def-site-eval.rs:14:20
|
--> $DIR/def-site-eval.rs:13:20
|
||||||
|
|
|
|
||||||
LL | const _<'_a>: () = panic!();
|
LL | const _<'_a>: () = panic!();
|
||||||
| ^^^^^^^^ evaluation panicked: explicit panic
|
| ^^^^^^^^ evaluation panicked: explicit panic
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
//! Test that we only evaluate free const items (their def site to be clear)
|
//! Test that we only evaluate free const items (their def site to be clear)
|
||||||
//! whose generics don't require monomorphization.
|
//! whose generics don't require monomorphization.
|
||||||
#![feature(generic_const_items)]
|
#![feature(generic_const_items)]
|
||||||
#![allow(incomplete_features)]
|
#![expect(incomplete_features)]
|
||||||
|
|
||||||
//@ revisions: fail pass
|
//@ revisions: fail pass
|
||||||
//@[fail] build-fail (we require monomorphization)
|
//@[pass] check-pass
|
||||||
//@[pass] build-pass (we require monomorphization)
|
|
||||||
|
|
||||||
const _<_T>: () = panic!();
|
const _<_T>: () = panic!();
|
||||||
const _<const _N: usize>: () = panic!();
|
const _<const _N: usize>: () = panic!();
|
||||||
|
|
||||||
#[cfg(fail)]
|
#[cfg(fail)]
|
||||||
const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation of `_::<'_>` failed
|
const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation of constant value failed
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|||||||
9
tests/ui/generic-const-items/def-site-predicates-wf.rs
Normal file
9
tests/ui/generic-const-items/def-site-predicates-wf.rs
Normal 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() {}
|
||||||
13
tests/ui/generic-const-items/def-site-predicates-wf.stderr
Normal file
13
tests/ui/generic-const-items/def-site-predicates-wf.stderr
Normal 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`.
|
||||||
Reference in New Issue
Block a user