Auto merge of #113210 - fee1-dead-contrib:effects-mvp, r=oli-obk
Effects/keyword generics MVP This adds `feature(effects)`, which adds `const host: bool` to the generics of const functions, const traits and const impls. This will be used to replace the current logic around const traits. r? `@oli-obk`
This commit is contained in:
commit
e4cd161006
15 changed files with 269 additions and 26 deletions
|
@ -2652,6 +2652,15 @@ pub struct NormalAttr {
|
||||||
pub tokens: Option<LazyAttrTokenStream>,
|
pub tokens: Option<LazyAttrTokenStream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NormalAttr {
|
||||||
|
pub fn from_ident(ident: Ident) -> Self {
|
||||||
|
Self {
|
||||||
|
item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None },
|
||||||
|
tokens: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||||
pub struct AttrItem {
|
pub struct AttrItem {
|
||||||
pub path: Path,
|
pub path: Path,
|
||||||
|
|
|
@ -673,14 +673,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
self.lower_attrs(
|
self.lower_attrs(
|
||||||
inner_hir_id,
|
inner_hir_id,
|
||||||
&[Attribute {
|
&[Attribute {
|
||||||
kind: AttrKind::Normal(ptr::P(NormalAttr {
|
kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(sym::track_caller, span)))),
|
||||||
item: AttrItem {
|
|
||||||
path: Path::from_ident(Ident::new(sym::track_caller, span)),
|
|
||||||
args: AttrArgs::Empty,
|
|
||||||
tokens: None,
|
|
||||||
},
|
|
||||||
tokens: None,
|
|
||||||
})),
|
|
||||||
id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(),
|
id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(),
|
||||||
style: AttrStyle::Outer,
|
style: AttrStyle::Outer,
|
||||||
span: unstable_span,
|
span: unstable_span,
|
||||||
|
|
|
@ -3,6 +3,7 @@ use super::ResolverAstLoweringExt;
|
||||||
use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
|
use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
|
||||||
use super::{FnDeclKind, LoweringContext, ParamMode};
|
use super::{FnDeclKind, LoweringContext, ParamMode};
|
||||||
|
|
||||||
|
use hir::definitions::DefPathData;
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::visit::AssocCtxt;
|
use rustc_ast::visit::AssocCtxt;
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
|
@ -257,7 +258,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
);
|
);
|
||||||
|
|
||||||
let itctx = ImplTraitContext::Universal;
|
let itctx = ImplTraitContext::Universal;
|
||||||
let (generics, decl) = this.lower_generics(generics, id, &itctx, |this| {
|
let (generics, decl) =
|
||||||
|
this.lower_generics(generics, header.constness, id, &itctx, |this| {
|
||||||
let ret_id = asyncness.opt_return_id();
|
let ret_id = asyncness.opt_return_id();
|
||||||
this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id)
|
this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id)
|
||||||
});
|
});
|
||||||
|
@ -295,6 +297,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
add_ty_alias_where_clause(&mut generics, *where_clauses, true);
|
add_ty_alias_where_clause(&mut generics, *where_clauses, true);
|
||||||
let (generics, ty) = self.lower_generics(
|
let (generics, ty) = self.lower_generics(
|
||||||
&generics,
|
&generics,
|
||||||
|
Const::No,
|
||||||
id,
|
id,
|
||||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| match ty {
|
|this| match ty {
|
||||||
|
@ -316,6 +319,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ItemKind::Enum(enum_definition, generics) => {
|
ItemKind::Enum(enum_definition, generics) => {
|
||||||
let (generics, variants) = self.lower_generics(
|
let (generics, variants) = self.lower_generics(
|
||||||
generics,
|
generics,
|
||||||
|
Const::No,
|
||||||
id,
|
id,
|
||||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| {
|
|this| {
|
||||||
|
@ -329,6 +333,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ItemKind::Struct(struct_def, generics) => {
|
ItemKind::Struct(struct_def, generics) => {
|
||||||
let (generics, struct_def) = self.lower_generics(
|
let (generics, struct_def) = self.lower_generics(
|
||||||
generics,
|
generics,
|
||||||
|
Const::No,
|
||||||
id,
|
id,
|
||||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| this.lower_variant_data(hir_id, struct_def),
|
|this| this.lower_variant_data(hir_id, struct_def),
|
||||||
|
@ -338,6 +343,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ItemKind::Union(vdata, generics) => {
|
ItemKind::Union(vdata, generics) => {
|
||||||
let (generics, vdata) = self.lower_generics(
|
let (generics, vdata) = self.lower_generics(
|
||||||
generics,
|
generics,
|
||||||
|
Const::No,
|
||||||
id,
|
id,
|
||||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| this.lower_variant_data(hir_id, vdata),
|
|this| this.lower_variant_data(hir_id, vdata),
|
||||||
|
@ -369,7 +375,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// parent lifetime.
|
// parent lifetime.
|
||||||
let itctx = ImplTraitContext::Universal;
|
let itctx = ImplTraitContext::Universal;
|
||||||
let (generics, (trait_ref, lowered_ty)) =
|
let (generics, (trait_ref, lowered_ty)) =
|
||||||
self.lower_generics(ast_generics, id, &itctx, |this| {
|
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
|
||||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||||
this.lower_trait_ref(
|
this.lower_trait_ref(
|
||||||
trait_ref,
|
trait_ref,
|
||||||
|
@ -410,8 +416,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
ItemKind::Trait(box Trait { is_auto, unsafety, generics, bounds, items }) => {
|
ItemKind::Trait(box Trait { is_auto, unsafety, generics, bounds, items }) => {
|
||||||
|
// FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible
|
||||||
|
let constness = attrs
|
||||||
|
.unwrap_or(&[])
|
||||||
|
.iter()
|
||||||
|
.find(|x| x.has_name(sym::const_trait))
|
||||||
|
.map_or(Const::No, |x| Const::Yes(x.span));
|
||||||
let (generics, (unsafety, items, bounds)) = self.lower_generics(
|
let (generics, (unsafety, items, bounds)) = self.lower_generics(
|
||||||
generics,
|
generics,
|
||||||
|
constness,
|
||||||
id,
|
id,
|
||||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| {
|
|this| {
|
||||||
|
@ -431,6 +444,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ItemKind::TraitAlias(generics, bounds) => {
|
ItemKind::TraitAlias(generics, bounds) => {
|
||||||
let (generics, bounds) = self.lower_generics(
|
let (generics, bounds) = self.lower_generics(
|
||||||
generics,
|
generics,
|
||||||
|
Const::No,
|
||||||
id,
|
id,
|
||||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| {
|
|this| {
|
||||||
|
@ -593,7 +607,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let fdec = &sig.decl;
|
let fdec = &sig.decl;
|
||||||
let itctx = ImplTraitContext::Universal;
|
let itctx = ImplTraitContext::Universal;
|
||||||
let (generics, (fn_dec, fn_args)) =
|
let (generics, (fn_dec, fn_args)) =
|
||||||
self.lower_generics(generics, i.id, &itctx, |this| {
|
self.lower_generics(generics, Const::No, i.id, &itctx, |this| {
|
||||||
(
|
(
|
||||||
// Disallow `impl Trait` in foreign items.
|
// Disallow `impl Trait` in foreign items.
|
||||||
this.lower_fn_decl(
|
this.lower_fn_decl(
|
||||||
|
@ -745,6 +759,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
|
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
|
||||||
let (generics, kind) = self.lower_generics(
|
let (generics, kind) = self.lower_generics(
|
||||||
&generics,
|
&generics,
|
||||||
|
Const::No,
|
||||||
i.id,
|
i.id,
|
||||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| {
|
|this| {
|
||||||
|
@ -843,6 +858,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
|
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
|
||||||
self.lower_generics(
|
self.lower_generics(
|
||||||
&generics,
|
&generics,
|
||||||
|
Const::No,
|
||||||
i.id,
|
i.id,
|
||||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| match ty {
|
|this| match ty {
|
||||||
|
@ -1201,7 +1217,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
||||||
let header = self.lower_fn_header(sig.header);
|
let header = self.lower_fn_header(sig.header);
|
||||||
let itctx = ImplTraitContext::Universal;
|
let itctx = ImplTraitContext::Universal;
|
||||||
let (generics, decl) = self.lower_generics(generics, id, &itctx, |this| {
|
let (generics, decl) =
|
||||||
|
self.lower_generics(generics, sig.header.constness, id, &itctx, |this| {
|
||||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async)
|
this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async)
|
||||||
});
|
});
|
||||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||||
|
@ -1275,6 +1292,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
fn lower_generics<T>(
|
fn lower_generics<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
|
constness: Const,
|
||||||
parent_node_id: NodeId,
|
parent_node_id: NodeId,
|
||||||
itctx: &ImplTraitContext,
|
itctx: &ImplTraitContext,
|
||||||
f: impl FnOnce(&mut Self) -> T,
|
f: impl FnOnce(&mut Self) -> T,
|
||||||
|
@ -1372,6 +1390,87 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
|
let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
|
||||||
predicates.extend(impl_trait_bounds.into_iter());
|
predicates.extend(impl_trait_bounds.into_iter());
|
||||||
|
|
||||||
|
// Desugar `~const` bound in generics into an additional `const host: bool` param
|
||||||
|
// if the effects feature is enabled.
|
||||||
|
if let Const::Yes(span) = constness && self.tcx.features().effects
|
||||||
|
// Do not add host param if it already has it (manually specified)
|
||||||
|
&& !params.iter().any(|x| {
|
||||||
|
self.attrs.get(&x.hir_id.local_id).map_or(false, |attrs| {
|
||||||
|
attrs.iter().any(|x| x.has_name(sym::rustc_host))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
{
|
||||||
|
let param_node_id = self.next_node_id();
|
||||||
|
let const_node_id = self.next_node_id();
|
||||||
|
let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
|
||||||
|
let anon_const: LocalDefId = self.create_def(def_id, const_node_id, DefPathData::AnonConst, span);
|
||||||
|
|
||||||
|
let hir_id = self.next_id();
|
||||||
|
let const_id = self.next_id();
|
||||||
|
let const_expr_id = self.next_id();
|
||||||
|
let bool_id = self.next_id();
|
||||||
|
|
||||||
|
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
|
||||||
|
self.children.push((anon_const, hir::MaybeOwner::NonOwner(const_id)));
|
||||||
|
|
||||||
|
let attr_id = self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id();
|
||||||
|
|
||||||
|
let attrs = self.arena.alloc_from_iter([
|
||||||
|
Attribute {
|
||||||
|
kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))),
|
||||||
|
span,
|
||||||
|
id: attr_id,
|
||||||
|
style: AttrStyle::Outer,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
self.attrs.insert(hir_id.local_id, attrs);
|
||||||
|
|
||||||
|
let const_body = self.lower_body(|this| {
|
||||||
|
(
|
||||||
|
&[],
|
||||||
|
hir::Expr {
|
||||||
|
hir_id: const_expr_id,
|
||||||
|
kind: hir::ExprKind::Lit(
|
||||||
|
this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }),
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let param = hir::GenericParam {
|
||||||
|
def_id,
|
||||||
|
hir_id,
|
||||||
|
name: hir::ParamName::Plain(Ident { name: sym::host, span }),
|
||||||
|
span,
|
||||||
|
kind: hir::GenericParamKind::Const {
|
||||||
|
ty: self.arena.alloc(self.ty(
|
||||||
|
span,
|
||||||
|
hir::TyKind::Path(hir::QPath::Resolved(
|
||||||
|
None,
|
||||||
|
self.arena.alloc(hir::Path {
|
||||||
|
res: Res::PrimTy(hir::PrimTy::Bool),
|
||||||
|
span,
|
||||||
|
segments: self.arena.alloc_from_iter([hir::PathSegment {
|
||||||
|
ident: Ident { name: sym::bool, span },
|
||||||
|
hir_id: bool_id,
|
||||||
|
res: Res::PrimTy(hir::PrimTy::Bool),
|
||||||
|
args: None,
|
||||||
|
infer_args: false,
|
||||||
|
}]),
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
default: Some(hir::AnonConst { def_id: anon_const, hir_id: const_id, body: const_body }),
|
||||||
|
},
|
||||||
|
colon_span: None,
|
||||||
|
pure_wrt_drop: false,
|
||||||
|
source: hir::GenericParamSource::Generics,
|
||||||
|
};
|
||||||
|
|
||||||
|
params.push(param);
|
||||||
|
}
|
||||||
|
|
||||||
let lowered_generics = self.arena.alloc(hir::Generics {
|
let lowered_generics = self.arena.alloc(hir::Generics {
|
||||||
params: self.arena.alloc_from_iter(params),
|
params: self.arena.alloc_from_iter(params),
|
||||||
predicates: self.arena.alloc_from_iter(predicates),
|
predicates: self.arena.alloc_from_iter(predicates),
|
||||||
|
|
|
@ -391,6 +391,8 @@ declare_features! (
|
||||||
(active, doc_masked, "1.21.0", Some(44027), None),
|
(active, doc_masked, "1.21.0", Some(44027), None),
|
||||||
/// Allows `dyn* Trait` objects.
|
/// Allows `dyn* Trait` objects.
|
||||||
(incomplete, dyn_star, "1.65.0", Some(102425), None),
|
(incomplete, dyn_star, "1.65.0", Some(102425), None),
|
||||||
|
// Uses generic effect parameters for ~const bounds
|
||||||
|
(active, effects, "CURRENT_RUSTC_VERSION", Some(102090), None),
|
||||||
/// Allows `X..Y` patterns.
|
/// Allows `X..Y` patterns.
|
||||||
(active, exclusive_range_pattern, "1.11.0", Some(37854), None),
|
(active, exclusive_range_pattern, "1.11.0", Some(37854), None),
|
||||||
/// Allows exhaustive pattern matching on types that contain uninhabited types.
|
/// Allows exhaustive pattern matching on types that contain uninhabited types.
|
||||||
|
|
|
@ -723,6 +723,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
and it is only intended to be used in `alloc`."
|
and it is only intended to be used in `alloc`."
|
||||||
),
|
),
|
||||||
|
|
||||||
|
rustc_attr!(
|
||||||
|
rustc_host, AttributeType::Normal, template!(Word), ErrorFollowing,
|
||||||
|
"#[rustc_host] annotates const generic parameters as the `host` effect param, \
|
||||||
|
and it is only intended for internal use and as a desugaring."
|
||||||
|
),
|
||||||
|
|
||||||
BuiltinAttribute {
|
BuiltinAttribute {
|
||||||
name: sym::rustc_diagnostic_item,
|
name: sym::rustc_diagnostic_item,
|
||||||
// FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
|
// FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::symbol::{kw, Symbol};
|
use rustc_span::symbol::{kw, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::{sym, Span};
|
||||||
|
|
||||||
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
use rustc_hir::*;
|
use rustc_hir::*;
|
||||||
|
@ -101,6 +101,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
param_def_id_to_index,
|
param_def_id_to_index,
|
||||||
has_self: generics.has_self,
|
has_self: generics.has_self,
|
||||||
has_late_bound_regions: generics.has_late_bound_regions,
|
has_late_bound_regions: generics.has_late_bound_regions,
|
||||||
|
host_effect_index: None,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// HACK(eddyb) this provides the correct generics when
|
// HACK(eddyb) this provides the correct generics when
|
||||||
|
@ -226,10 +227,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
let has_self = opt_self.is_some();
|
let has_self = opt_self.is_some();
|
||||||
let mut parent_has_self = false;
|
let mut parent_has_self = false;
|
||||||
let mut own_start = has_self as u32;
|
let mut own_start = has_self as u32;
|
||||||
|
let mut host_effect_index = None;
|
||||||
let parent_count = parent_def_id.map_or(0, |def_id| {
|
let parent_count = parent_def_id.map_or(0, |def_id| {
|
||||||
let generics = tcx.generics_of(def_id);
|
let generics = tcx.generics_of(def_id);
|
||||||
assert!(!has_self);
|
assert!(!has_self);
|
||||||
parent_has_self = generics.has_self;
|
parent_has_self = generics.has_self;
|
||||||
|
host_effect_index = generics.host_effect_index;
|
||||||
own_start = generics.count() as u32;
|
own_start = generics.count() as u32;
|
||||||
generics.parent_count + generics.params.len()
|
generics.parent_count + generics.params.len()
|
||||||
});
|
});
|
||||||
|
@ -251,11 +254,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
|
|
||||||
// Now create the real type and const parameters.
|
// Now create the real type and const parameters.
|
||||||
let type_start = own_start - has_self as u32 + params.len() as u32;
|
let type_start = own_start - has_self as u32 + params.len() as u32;
|
||||||
let mut i = 0;
|
let mut i: u32 = 0;
|
||||||
let mut next_index = || {
|
let mut next_index = || {
|
||||||
let prev = i;
|
let prev = i;
|
||||||
i += 1;
|
i += 1;
|
||||||
prev as u32 + type_start
|
prev + type_start
|
||||||
};
|
};
|
||||||
|
|
||||||
const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
|
const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
|
||||||
|
@ -295,7 +298,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
GenericParamKind::Const { default, .. } => {
|
GenericParamKind::Const { default, .. } => {
|
||||||
if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
|
let is_host_param = tcx.has_attr(param.def_id, sym::rustc_host);
|
||||||
|
|
||||||
|
if !matches!(allow_defaults, Defaults::Allowed)
|
||||||
|
&& default.is_some()
|
||||||
|
// `rustc_host` effect params are allowed to have defaults.
|
||||||
|
&& !is_host_param
|
||||||
|
{
|
||||||
tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
param.span,
|
param.span,
|
||||||
"defaults for const parameters are only allowed in \
|
"defaults for const parameters are only allowed in \
|
||||||
|
@ -303,8 +312,18 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let index = next_index();
|
||||||
|
|
||||||
|
if is_host_param {
|
||||||
|
if let Some(idx) = host_effect_index {
|
||||||
|
bug!("parent also has host effect param? index: {idx}, def: {def_id:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
host_effect_index = Some(parent_count + index as usize);
|
||||||
|
}
|
||||||
|
|
||||||
Some(ty::GenericParamDef {
|
Some(ty::GenericParamDef {
|
||||||
index: next_index(),
|
index,
|
||||||
name: param.name.ident().name,
|
name: param.name.ident().name,
|
||||||
def_id: param.def_id.to_def_id(),
|
def_id: param.def_id.to_def_id(),
|
||||||
pure_wrt_drop: param.pure_wrt_drop,
|
pure_wrt_drop: param.pure_wrt_drop,
|
||||||
|
@ -356,6 +375,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
param_def_id_to_index,
|
param_def_id_to_index,
|
||||||
has_self: has_self || parent_has_self,
|
has_self: has_self || parent_has_self,
|
||||||
has_late_bound_regions: has_late_bound_regions(tcx, node),
|
has_late_bound_regions: has_late_bound_regions(tcx, node),
|
||||||
|
host_effect_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,9 @@ use crate::type_error_struct;
|
||||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||||
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey};
|
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{self, CtorKind, Namespace, Res};
|
use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_hir::HirId;
|
||||||
use rustc_hir_analysis::autoderef::Autoderef;
|
use rustc_hir_analysis::autoderef::Autoderef;
|
||||||
use rustc_infer::{
|
use rustc_infer::{
|
||||||
infer,
|
infer,
|
||||||
|
@ -376,15 +377,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let (fn_sig, def_id) = match *callee_ty.kind() {
|
let (fn_sig, def_id) = match *callee_ty.kind() {
|
||||||
ty::FnDef(def_id, subst) => {
|
ty::FnDef(def_id, substs) => {
|
||||||
let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst);
|
self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, substs);
|
||||||
|
let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs);
|
||||||
|
|
||||||
// Unit testing: function items annotated with
|
// Unit testing: function items annotated with
|
||||||
// `#[rustc_evaluate_where_clauses]` trigger special output
|
// `#[rustc_evaluate_where_clauses]` trigger special output
|
||||||
// to let us test the trait evaluation system.
|
// to let us test the trait evaluation system.
|
||||||
if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
|
if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
|
||||||
let predicates = self.tcx.predicates_of(def_id);
|
let predicates = self.tcx.predicates_of(def_id);
|
||||||
let predicates = predicates.instantiate(self.tcx, subst);
|
let predicates = predicates.instantiate(self.tcx, substs);
|
||||||
for (predicate, predicate_span) in predicates {
|
for (predicate, predicate_span) in predicates {
|
||||||
let obligation = Obligation::new(
|
let obligation = Obligation::new(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
|
@ -405,6 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
(fn_sig, Some(def_id))
|
(fn_sig, Some(def_id))
|
||||||
}
|
}
|
||||||
|
// FIXME(effects): these arms should error because we can't enforce them
|
||||||
ty::FnPtr(sig) => (sig, None),
|
ty::FnPtr(sig) => (sig, None),
|
||||||
_ => {
|
_ => {
|
||||||
for arg in arg_exprs {
|
for arg in arg_exprs {
|
||||||
|
@ -739,6 +742,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn_sig.output()
|
fn_sig.output()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip(self, span))]
|
||||||
|
pub(super) fn enforce_context_effects(
|
||||||
|
&self,
|
||||||
|
call_expr_hir: HirId,
|
||||||
|
span: Span,
|
||||||
|
callee_did: DefId,
|
||||||
|
callee_substs: SubstsRef<'tcx>,
|
||||||
|
) {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
|
||||||
|
if !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the constness required by the context.
|
||||||
|
let context = tcx.hir().enclosing_body_owner(call_expr_hir);
|
||||||
|
let const_context = tcx.hir().body_const_context(context);
|
||||||
|
|
||||||
|
let kind = tcx.def_kind(context.to_def_id());
|
||||||
|
debug_assert_ne!(kind, DefKind::ConstParam);
|
||||||
|
|
||||||
|
if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) {
|
||||||
|
trace!("do not const check this context");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let effect = match const_context {
|
||||||
|
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_,
|
||||||
|
Some(hir::ConstContext::ConstFn) => {
|
||||||
|
let substs = ty::InternalSubsts::identity_for_item(tcx, context);
|
||||||
|
substs.host_effect_param().expect("ConstContext::Maybe must have host effect param")
|
||||||
|
}
|
||||||
|
None => tcx.consts.true_,
|
||||||
|
};
|
||||||
|
|
||||||
|
let generics = tcx.generics_of(callee_did);
|
||||||
|
|
||||||
|
trace!(?effect, ?generics, ?callee_substs);
|
||||||
|
|
||||||
|
if let Some(idx) = generics.host_effect_index {
|
||||||
|
let param = callee_substs.const_at(idx);
|
||||||
|
let cause = self.misc(span);
|
||||||
|
match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
|
||||||
|
Ok(infer::InferOk { obligations, value: () }) => {
|
||||||
|
self.register_predicates(obligations);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// FIXME(effects): better diagnostic
|
||||||
|
self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn confirm_overloaded_call(
|
fn confirm_overloaded_call(
|
||||||
&self,
|
&self,
|
||||||
call_expr: &'tcx hir::Expr<'tcx>,
|
call_expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
|
|
@ -1274,6 +1274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
|
// We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
|
||||||
// trigger this codepath causing `structurally_resolve_type` to emit an error.
|
// trigger this codepath causing `structurally_resolve_type` to emit an error.
|
||||||
|
|
||||||
|
self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.substs);
|
||||||
self.write_method_call(expr.hir_id, method);
|
self.write_method_call(expr.hir_id, method);
|
||||||
Ok(method)
|
Ok(method)
|
||||||
}
|
}
|
||||||
|
|
|
@ -533,6 +533,10 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
|
||||||
|
|
||||||
fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) {
|
fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) {
|
||||||
if let GenericParamKind::Const { .. } = param.kind {
|
if let GenericParamKind::Const { .. } = param.kind {
|
||||||
|
// `rustc_host` params are explicitly allowed to be lowercase.
|
||||||
|
if cx.tcx.has_attr(param.def_id, sym::rustc_host) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
NonUpperCaseGlobals::check_upper_case(cx, "const parameter", ¶m.name.ident());
|
NonUpperCaseGlobals::check_upper_case(cx, "const parameter", ¶m.name.ident());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,6 +320,8 @@ pub struct CommonLifetimes<'tcx> {
|
||||||
|
|
||||||
pub struct CommonConsts<'tcx> {
|
pub struct CommonConsts<'tcx> {
|
||||||
pub unit: Const<'tcx>,
|
pub unit: Const<'tcx>,
|
||||||
|
pub true_: Const<'tcx>,
|
||||||
|
pub false_: Const<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> CommonTypes<'tcx> {
|
impl<'tcx> CommonTypes<'tcx> {
|
||||||
|
@ -417,6 +419,14 @@ impl<'tcx> CommonConsts<'tcx> {
|
||||||
kind: ty::ConstKind::Value(ty::ValTree::zst()),
|
kind: ty::ConstKind::Value(ty::ValTree::zst()),
|
||||||
ty: types.unit,
|
ty: types.unit,
|
||||||
}),
|
}),
|
||||||
|
true_: mk_const(ty::ConstData {
|
||||||
|
kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::TRUE)),
|
||||||
|
ty: types.bool,
|
||||||
|
}),
|
||||||
|
false_: mk_const(ty::ConstData {
|
||||||
|
kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::FALSE)),
|
||||||
|
ty: types.bool,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,6 +135,9 @@ pub struct Generics {
|
||||||
|
|
||||||
pub has_self: bool,
|
pub has_self: bool,
|
||||||
pub has_late_bound_regions: Option<Span>,
|
pub has_late_bound_regions: Option<Span>,
|
||||||
|
|
||||||
|
// The index of the host effect when substituted. (i.e. might be index to parent substs)
|
||||||
|
pub host_effect_index: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Generics {
|
impl<'tcx> Generics {
|
||||||
|
|
|
@ -11,6 +11,7 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
use rustc_serialize::{self, Decodable, Encodable};
|
use rustc_serialize::{self, Decodable, Encodable};
|
||||||
|
use rustc_span::sym;
|
||||||
use rustc_type_ir::WithCachedTypeInfo;
|
use rustc_type_ir::WithCachedTypeInfo;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
@ -451,6 +452,10 @@ impl<'tcx> InternalSubsts<'tcx> {
|
||||||
pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> {
|
pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> {
|
||||||
tcx.mk_substs_from_iter(self.iter().take(generics.count()))
|
tcx.mk_substs_from_iter(self.iter().take(generics.count()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn host_effect_param(&'tcx self) -> Option<ty::Const<'tcx>> {
|
||||||
|
self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for SubstsRef<'tcx> {
|
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for SubstsRef<'tcx> {
|
||||||
|
|
|
@ -656,6 +656,7 @@ symbols! {
|
||||||
dyn_trait,
|
dyn_trait,
|
||||||
e,
|
e,
|
||||||
edition_panic,
|
edition_panic,
|
||||||
|
effects,
|
||||||
eh_catch_typeinfo,
|
eh_catch_typeinfo,
|
||||||
eh_personality,
|
eh_personality,
|
||||||
emit,
|
emit,
|
||||||
|
@ -793,6 +794,7 @@ symbols! {
|
||||||
hexagon_target_feature,
|
hexagon_target_feature,
|
||||||
hidden,
|
hidden,
|
||||||
homogeneous_aggregate,
|
homogeneous_aggregate,
|
||||||
|
host,
|
||||||
html_favicon_url,
|
html_favicon_url,
|
||||||
html_logo_url,
|
html_logo_url,
|
||||||
html_no_source,
|
html_no_source,
|
||||||
|
@ -1284,6 +1286,7 @@ symbols! {
|
||||||
rustc_evaluate_where_clauses,
|
rustc_evaluate_where_clauses,
|
||||||
rustc_expected_cgu_reuse,
|
rustc_expected_cgu_reuse,
|
||||||
rustc_has_incoherent_inherent_impls,
|
rustc_has_incoherent_inherent_impls,
|
||||||
|
rustc_host,
|
||||||
rustc_if_this_changed,
|
rustc_if_this_changed,
|
||||||
rustc_inherit_overflow_checks,
|
rustc_inherit_overflow_checks,
|
||||||
rustc_insignificant_dtor,
|
rustc_insignificant_dtor,
|
||||||
|
|
|
@ -337,6 +337,7 @@ fn associated_type_for_impl_trait_in_trait(
|
||||||
param_def_id_to_index,
|
param_def_id_to_index,
|
||||||
has_self: opaque_ty_generics.has_self,
|
has_self: opaque_ty_generics.has_self,
|
||||||
has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
|
has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
|
||||||
|
host_effect_index: parent_generics.host_effect_index,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -415,6 +416,7 @@ fn associated_type_for_impl_trait_in_impl(
|
||||||
param_def_id_to_index,
|
param_def_id_to_index,
|
||||||
has_self: false,
|
has_self: false,
|
||||||
has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
|
has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
|
||||||
|
host_effect_index: parent_generics.host_effect_index,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
// gate-test-effects
|
||||||
|
// ^ effects doesn't have a gate so we will trick tidy into thinking this is a gate test
|
||||||
|
|
||||||
|
#![feature(const_trait_impl, effects, rustc_attrs)]
|
||||||
|
|
||||||
|
// ensure we are passing in the correct host effect in always const contexts.
|
||||||
|
|
||||||
|
pub const fn hmm</* T, */ #[rustc_host] const host: bool = true>() -> usize {
|
||||||
|
if host {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
let x = hmm();
|
||||||
|
assert!(0 == x);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* FIXME(effects)
|
||||||
|
pub const fn uwu(x: [u8; hmm::<()>()]) {
|
||||||
|
let [] = x;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue