Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ pub(crate) struct TypeConstParser;
impl<S: Stage> NoArgsAttributeParser<S> for TypeConstParser {
const PATH: &[Symbol] = &[sym::type_const];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocConst)]);
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Const), Allow(Target::AssocConst)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::TypeConst;
}

Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3065,7 +3065,7 @@ macro_rules! expect_methods_self_kind {
$(
#[track_caller]
pub fn $name(&self) -> $ret_ty {
let $pat = &self.kind else { expect_failed(stringify!($ident), self) };
let $pat = &self.kind else { expect_failed(stringify!($name), self) };
$ret_val
}
)*
Expand All @@ -3077,7 +3077,7 @@ macro_rules! expect_methods_self {
$(
#[track_caller]
pub fn $name(&self) -> $ret_ty {
let $pat = self else { expect_failed(stringify!($ident), self) };
let $pat = self else { expect_failed(stringify!($name), self) };
$ret_val
}
)*
Expand Down Expand Up @@ -4790,6 +4790,11 @@ impl<'hir> Node<'hir> {
ForeignItemKind::Static(ty, ..) => Some(ty),
_ => None,
},
Node::GenericParam(param) => match param.kind {
GenericParamKind::Lifetime { .. } => None,
GenericParamKind::Type { default, .. } => default,
GenericParamKind::Const { ty, .. } => Some(ty),
},
_ => None,
}
}
Expand Down
60 changes: 47 additions & 13 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -757,22 +757,18 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
}

match tcx.def_kind(def_id) {
def_kind @ (DefKind::Static { .. } | DefKind::Const) => {
DefKind::Static { .. } => {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
match def_kind {
DefKind::Static { .. } => {
check_static_inhabited(tcx, def_id);
check_static_linkage(tcx, def_id);
let ty = tcx.type_of(def_id).instantiate_identity();
res = res.and(wfcheck::check_static_item(
tcx, def_id, ty, /* should_check_for_sync */ true,
));
}
DefKind::Const => res = res.and(wfcheck::check_const_item(tcx, def_id)),
_ => unreachable!(),
}

check_static_inhabited(tcx, def_id);
check_static_linkage(tcx, def_id);
let ty = tcx.type_of(def_id).instantiate_identity();
res = res.and(wfcheck::check_static_item(
tcx, def_id, ty, /* should_check_for_sync */ true,
));

// Only `Node::Item` and `Node::ForeignItem` still have HIR based
// checks. Returning early here does not miss any checks and
// avoids this query from having a direct dependency edge on the HIR
Expand Down Expand Up @@ -900,6 +896,39 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
// avoids this query from having a direct dependency edge on the HIR
return res;
}
DefKind::Const => {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);

res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
let ty = tcx.type_of(def_id).instantiate_identity();
let ty_span = tcx.ty_span(def_id);
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,
def_id,
ObligationCauseCode::SizedConstOrStatic,
),
tcx.param_env(def_id),
ty,
tcx.require_lang_item(LangItem::Sized, ty_span),
);
check_where_clauses(wfcx, def_id);

if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) {
wfcheck::check_type_const(wfcx, def_id, ty, true)?;
}
Ok(())
}));

// Only `Node::Item` and `Node::ForeignItem` still have HIR based
// checks. Returning early here does not miss any checks and
// avoids this query from having a direct dependency edge on the HIR
return res;
}
DefKind::TyAlias => {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
Expand All @@ -920,6 +949,11 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
}));
check_variances_for_type_defn(tcx, def_id);
}

// Only `Node::Item` and `Node::ForeignItem` still have HIR based
// checks. Returning early here does not miss any checks and
// avoids this query from having a direct dependency edge on the HIR
return res;
}
DefKind::ForeignMod => {
let it = tcx.hir_expect_item(def_id);
Expand Down
37 changes: 36 additions & 1 deletion compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};
use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, find_attr, intravisit};
use rustc_infer::infer::{self, BoundRegionConversionTime, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
Expand Down Expand Up @@ -1984,12 +1985,46 @@ fn compare_impl_const<'tcx>(
trait_const_item: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorGuaranteed> {
compare_type_const(tcx, impl_const_item, trait_const_item)?;
compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?;
compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?;
check_region_bounds_on_impl_item(tcx, impl_const_item, trait_const_item, false)?;
compare_const_predicate_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref)
}

fn compare_type_const<'tcx>(
tcx: TyCtxt<'tcx>,
impl_const_item: ty::AssocItem,
trait_const_item: ty::AssocItem,
) -> Result<(), ErrorGuaranteed> {
let impl_is_type_const =
find_attr!(tcx.get_all_attrs(impl_const_item.def_id), AttributeKind::TypeConst(_));
let trait_type_const_span = find_attr!(
tcx.get_all_attrs(trait_const_item.def_id),
AttributeKind::TypeConst(sp) => *sp
);

if let Some(trait_type_const_span) = trait_type_const_span
&& !impl_is_type_const
{
return Err(tcx
.dcx()
.struct_span_err(
tcx.def_span(impl_const_item.def_id),
"implementation of `#[type_const]` const must be marked with `#[type_const]`",
)
.with_span_note(
MultiSpan::from_spans(vec![
tcx.def_span(trait_const_item.def_id),
trait_type_const_span,
]),
"trait declaration of const is marked with `#[type_const]`",
)
.emit());
}
Ok(())
}

/// The equivalent of [compare_method_predicate_entailment], but for associated constants
/// instead of associated functions.
// FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`.
Expand Down
125 changes: 63 additions & 62 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use rustc_abi::ExternAbi;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{AmbigArg, ItemKind};
use rustc_hir::{AmbigArg, ItemKind, find_attr};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin, TyCtxtInferExt};
use rustc_lint_defs::builtin::SUPERTRAIT_ITEM_SHADOWING_DEFINITION;
Expand Down Expand Up @@ -925,11 +926,11 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &ty::GenericParamDef) -> Result<(), Er
#[instrument(level = "debug", skip(tcx))]
pub(crate) fn check_associated_item(
tcx: TyCtxt<'_>,
item_id: LocalDefId,
def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
let loc = Some(WellFormedLoc::Ty(item_id));
enter_wf_checking_ctxt(tcx, item_id, |wfcx| {
let item = tcx.associated_item(item_id);
let loc = Some(WellFormedLoc::Ty(def_id));
enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
let item = tcx.associated_item(def_id);

// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
Expand All @@ -942,36 +943,45 @@ pub(crate) fn check_associated_item(
}
};

let span = tcx.def_span(item_id);
let span = tcx.def_span(def_id);

match item.kind {
ty::AssocKind::Const { .. } => {
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
let ty = tcx.type_of(def_id).instantiate_identity();
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
check_sized_if_body(
wfcx,
item.def_id.expect_local(),
ty,
Some(span),
ObligationCauseCode::SizedConstOrStatic,
);

let has_value = item.defaultness(tcx).has_value();
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) {
check_type_const(wfcx, def_id, ty, has_value)?;
}

if has_value {
let code = ObligationCauseCode::SizedConstOrStatic;
wfcx.register_bound(
ObligationCause::new(span, def_id, code),
wfcx.param_env,
ty,
tcx.require_lang_item(LangItem::Sized, span),
);
}

Ok(())
}
ty::AssocKind::Fn { .. } => {
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
let sig = tcx.fn_sig(def_id).instantiate_identity();
let hir_sig =
tcx.hir_node_by_def_id(item_id).fn_sig().expect("bad signature for method");
check_fn_or_method(wfcx, sig, hir_sig.decl, item_id);
tcx.hir_node_by_def_id(def_id).fn_sig().expect("bad signature for method");
check_fn_or_method(wfcx, sig, hir_sig.decl, def_id);
check_method_receiver(wfcx, hir_sig, item, self_ty)
}
ty::AssocKind::Type { .. } => {
if let ty::AssocContainer::Trait = item.container {
check_associated_type_bounds(wfcx, item, span)
}
if item.defaultness(tcx).has_value() {
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
let ty = tcx.type_of(def_id).instantiate_identity();
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
}
Ok(())
Expand Down Expand Up @@ -1222,28 +1232,36 @@ pub(crate) fn check_static_item<'tcx>(
})
}

pub(crate) fn check_const_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
let ty = tcx.type_of(def_id).instantiate_identity();
let ty_span = tcx.ty_span(def_id);
let ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(def_id)), ty);
#[instrument(level = "debug", skip(wfcx))]
pub(super) fn check_type_const<'tcx>(
wfcx: &WfCheckingCtxt<'_, 'tcx>,
def_id: LocalDefId,
item_ty: Ty<'tcx>,
has_value: bool,
) -> Result<(), ErrorGuaranteed> {
let tcx = wfcx.tcx();
let span = tcx.def_span(def_id);

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, ty_span),
);
wfcx.register_bound(
ObligationCause::new(span, def_id, ObligationCauseCode::ConstParam(item_ty)),
wfcx.param_env,
item_ty,
tcx.require_lang_item(LangItem::ConstParamTy, span),
);

check_where_clauses(wfcx, def_id);
if has_value {
let raw_ct = tcx.const_of_item(def_id).instantiate_identity();
let norm_ct = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), raw_ct);
wfcx.register_wf_obligation(span, Some(WellFormedLoc::Ty(def_id)), norm_ct.into());

Ok(())
})
wfcx.register_obligation(Obligation::new(
tcx,
ObligationCause::new(span, def_id, ObligationCauseCode::WellFormed(None)),
wfcx.param_env,
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(norm_ct, item_ty)),
));
}
Ok(())
}

#[instrument(level = "debug", skip(tcx, impl_))]
Expand Down Expand Up @@ -1583,33 +1601,16 @@ fn check_fn_or_method<'tcx>(
}

// If the function has a body, additionally require that the return type is sized.
check_sized_if_body(
wfcx,
def_id,
sig.output(),
match hir_decl.output {
hir::FnRetTy::Return(ty) => Some(ty.span),
hir::FnRetTy::DefaultReturn(_) => None,
},
ObligationCauseCode::SizedReturnType,
);
}

fn check_sized_if_body<'tcx>(
wfcx: &WfCheckingCtxt<'_, 'tcx>,
def_id: LocalDefId,
ty: Ty<'tcx>,
maybe_span: Option<Span>,
code: ObligationCauseCode<'tcx>,
) {
let tcx = wfcx.tcx();
if let Some(body) = tcx.hir_maybe_body_owned_by(def_id) {
let span = maybe_span.unwrap_or(body.value.span);
let span = match hir_decl.output {
hir::FnRetTy::Return(ty) => ty.span,
hir::FnRetTy::DefaultReturn(_) => body.value.span,
};

wfcx.register_bound(
ObligationCause::new(span, def_id, code),
ObligationCause::new(span, def_id, ObligationCauseCode::SizedReturnType),
wfcx.param_env,
ty,
sig.output(),
tcx.require_lang_item(LangItem::Sized, span),
);
}
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1600,8 +1600,12 @@ fn const_of_item<'tcx>(
};
let ct_arg = match ct_rhs {
hir::ConstItemRhs::TypeConst(ct_arg) => ct_arg,
hir::ConstItemRhs::Body(body_id) => {
bug!("cannot call const_of_item on a non-type_const {body_id:?}")
hir::ConstItemRhs::Body(_) => {
let e = tcx.dcx().span_delayed_bug(
tcx.def_span(def_id),
"cannot call const_of_item on a non-type_const",
);
return ty::EarlyBinder::bind(Const::new_error(tcx, e));
}
};
let icx = ItemCtxt::new(tcx, def_id);
Expand Down
Loading
Loading