Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the min_const_generics feature gate #74877

Merged
merged 7 commits into from
Aug 8, 2020
Merged
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
24 changes: 24 additions & 0 deletions src/librustc_ast/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,30 @@ impl Expr {
}
}

/// Is this expr either `N`, or `{ N }`.
///
/// If this is not the case, name resolution does not resolve `N` when using
/// `feature(min_const_generics)` as more complex expressions are not supported.
pub fn is_potential_trivial_const_param(&self) -> bool {
let this = if let ExprKind::Block(ref block, None) = self.kind {
if block.stmts.len() == 1 {
if let StmtKind::Expr(ref expr) = block.stmts[0].kind { expr } else { self }
} else {
self
}
} else {
self
};

if let ExprKind::Path(None, ref path) = this.kind {
if path.segments.len() == 1 && path.segments[0].args.is_none() {
return true;
}
}

false
}

pub fn to_bound(&self) -> Option<GenericBound> {
match &self.kind {
ExprKind::Path(None, path) => Some(GenericBound::Trait(
Expand Down
8 changes: 7 additions & 1 deletion src/librustc_ast_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,13 @@ fn validate_generic_param_order<'a>(
span,
&format!(
"reorder the parameters: lifetimes, then types{}",
if sess.features_untracked().const_generics { ", then consts" } else { "" },
if sess.features_untracked().const_generics
|| sess.features_untracked().min_const_generics
{
", then consts"
} else {
""
},
),
ordered_params.clone(),
Applicability::MachineApplicable,
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_ast_passes/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,12 +526,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {

fn visit_generic_param(&mut self, param: &'a GenericParam) {
if let GenericParamKind::Const { .. } = param.kind {
gate_feature_post!(
gate_feature_fn!(
&self,
const_generics,
|x: &Features| x.const_generics || x.min_const_generics,
param.ident.span,
sym::min_const_generics,
"const generics are unstable"
)
);
}
visit::walk_generic_param(self, param)
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_feature/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,9 @@ declare_features! (
/// Alloc calling `transmute` in const fn
(active, const_fn_transmute, "1.46.0", Some(53605), None),

/// The smallest useful subset of `const_generics`.
(active, min_const_generics, "1.46.0", Some(74878), None),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be 1.47.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx, opened #75290


// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_middle/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1380,7 +1380,9 @@ impl<'tcx> TyCtxt<'tcx> {
/// we still evaluate them eagerly.
#[inline]
pub fn lazy_normalization(self) -> bool {
self.features().const_generics || self.features().lazy_normalization_consts
let features = self.features();
// Note: We do not enable lazy normalization for `features.min_const_generics`.
features.const_generics || features.lazy_normalization_consts
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_parse/parser/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl<'a> Parser<'a> {
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;

self.sess.gated_spans.gate(sym::const_generics, const_span.to(self.prev_token.span));
self.sess.gated_spans.gate(sym::min_const_generics, const_span.to(self.prev_token.span));

Ok(GenericParam {
ident,
Expand Down
17 changes: 17 additions & 0 deletions src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,23 @@ impl<'a> Resolver<'a> {
);
err
}
ResolutionError::ParamInNonTrivialAnonConst(name) => {
let mut err = self.session.struct_span_err(
span,
"generic parameters must not be used inside of non trivial constant values",
);
err.span_label(
span,
&format!(
"non-trivial anonymous constants must not depend on the parameter `{}`",
name
),
);
err.help(
&format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name)
);
err
}
ResolutionError::SelfInTyParamDefault => {
let mut err = struct_span_err!(
self.session,
Expand Down
40 changes: 27 additions & 13 deletions src/librustc_resolve/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ crate enum RibKind<'a> {
ItemRibKind(HasGenericParams),

/// We're in a constant item. Can't refer to dynamic stuff.
ConstantItemRibKind,
ConstantItemRibKind(bool),

/// We passed through a module.
ModuleRibKind(Module<'a>),
Expand All @@ -137,7 +137,7 @@ impl RibKind<'_> {
NormalRibKind
| ClosureOrAsyncRibKind
| FnItemRibKind
| ConstantItemRibKind
| ConstantItemRibKind(_)
| ModuleRibKind(_)
| MacroDefinition(_)
| ConstParamTyRibKind => false,
Expand Down Expand Up @@ -426,7 +426,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
}
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
debug!("visit_anon_const {:?}", constant);
self.with_constant_rib(|this| {
self.with_constant_rib(constant.value.is_potential_trivial_const_param(), |this| {
visit::walk_anon_const(this, constant);
});
}
Expand Down Expand Up @@ -628,7 +628,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
if !check_ns(TypeNS) && check_ns(ValueNS) {
// This must be equivalent to `visit_anon_const`, but we cannot call it
// directly due to visitor lifetimes so we have to copy-paste some code.
self.with_constant_rib(|this| {
self.with_constant_rib(true, |this| {
this.smart_resolve_path(
ty.id,
qself.as_ref(),
Expand Down Expand Up @@ -829,7 +829,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
| ClosureOrAsyncRibKind
| FnItemRibKind
| ItemRibKind(..)
| ConstantItemRibKind
| ConstantItemRibKind(_)
| ModuleRibKind(..)
| ForwardTyParamBanRibKind
| ConstParamTyRibKind => {
Expand Down Expand Up @@ -948,7 +948,14 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// Only impose the restrictions of `ConstRibKind` for an
// actual constant expression in a provided default.
if let Some(expr) = default {
this.with_constant_rib(|this| this.visit_expr(expr));
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.with_constant_rib(true, |this| {
this.visit_expr(expr)
});
}
}
AssocItemKind::Fn(_, _, generics, _) => {
Expand Down Expand Up @@ -989,7 +996,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.with_item_rib(HasGenericParams::No, |this| {
this.visit_ty(ty);
if let Some(expr) = expr {
this.with_constant_rib(|this| this.visit_expr(expr));
this.with_constant_rib(expr.is_potential_trivial_const_param(), |this| {
this.visit_expr(expr)
});
}
});
}
Expand Down Expand Up @@ -1086,11 +1095,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
}

fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
fn with_constant_rib(&mut self, trivial: bool, f: impl FnOnce(&mut Self)) {
debug!("with_constant_rib");
self.with_rib(ValueNS, ConstantItemRibKind, |this| {
this.with_rib(TypeNS, ConstantItemRibKind, |this| {
this.with_label_rib(ConstantItemRibKind, f);
self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| {
this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| {
this.with_label_rib(ConstantItemRibKind(trivial), f);
})
});
}
Expand Down Expand Up @@ -1220,7 +1229,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
for item in impl_items {
use crate::ResolutionError::*;
match &item.kind {
AssocItemKind::Const(..) => {
AssocItemKind::Const(_default, _ty, _expr) => {
debug!("resolve_implementation AssocItemKind::Const",);
// If this is a trait impl, ensure the const
// exists in trait
Expand All @@ -1231,7 +1240,12 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|n, s| ConstNotMemberOfTrait(n, s),
);

this.with_constant_rib(|this| {
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.with_constant_rib(true, |this| {
visit::walk_assoc_item(this, item, AssocCtxt::Impl)
});
}
Expand Down
32 changes: 29 additions & 3 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ enum ResolutionError<'a> {
ParamInTyOfConstParam(Symbol),
/// constant values inside of type parameter defaults must not depend on generic parameters.
ParamInAnonConstInTyDefault(Symbol),
/// generic parameters must not be used inside of non trivial constant values.
///
/// This error is only emitted when using `min_const_generics`.
ParamInNonTrivialAnonConst(Symbol),
/// Error E0735: type parameters with a default cannot use `Self`
SelfInTyParamDefault,
/// Error E0767: use of unreachable label
Expand Down Expand Up @@ -2507,7 +2511,7 @@ impl<'a> Resolver<'a> {
res_err = Some(CannotCaptureDynamicEnvironmentInFnItem);
}
}
ConstantItemRibKind => {
ConstantItemRibKind(_) => {
// Still doesn't deal with upvars
if record_used {
self.report_error(span, AttemptToUseNonConstantValueInConstant);
Expand Down Expand Up @@ -2546,7 +2550,18 @@ impl<'a> Resolver<'a> {
in_ty_param_default = true;
continue;
}
ConstantItemRibKind => {
ConstantItemRibKind(trivial) => {
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !trivial && self.session.features_untracked().min_const_generics {
if record_used {
self.report_error(
span,
ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
);
}
return Res::Err;
}

if in_ty_param_default {
if record_used {
self.report_error(
Expand Down Expand Up @@ -2612,7 +2627,18 @@ impl<'a> Resolver<'a> {
in_ty_param_default = true;
continue;
}
ConstantItemRibKind => {
ConstantItemRibKind(trivial) => {
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !trivial && self.session.features_untracked().min_const_generics {
if record_used {
self.report_error(
span,
ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
);
}
return Res::Err;
}

if in_ty_param_default {
if record_used {
self.report_error(
Expand Down
1 change: 1 addition & 0 deletions src/librustc_span/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ symbols! {
min_align_of,
min_align_of_val,
min_const_fn,
min_const_generics,
min_const_unsafe_fn,
min_specialization,
minnumf32,
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,9 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// HACK(eddyb) this provides the correct generics when
// `feature(const_generics)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
//
// Note that we do not supply the parent generics when using
// `feature(min_const_generics)`.
Some(parent_def_id.to_def_id())
} else {
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
Expand Down
44 changes: 31 additions & 13 deletions src/librustc_typeck/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,21 +326,39 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
GenericParamKind::Const { ty: ref hir_ty, .. } => {
let ty = icx.to_ty(hir_ty);
let err = match ty.peel_refs().kind {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
let err_ty_str;
let err = if tcx.features().min_const_generics {
match ty.kind {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => {
err_ty_str = format!("`{}`", ty);
Some(err_ty_str.as_str())
}
}
} else {
match ty.peel_refs().kind {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
}
};
if let Some(unsupported_type) = err {
tcx.sess
.struct_span_err(
hir_ty.span,
&format!(
"using {} as const generic parameters is forbidden",
unsupported_type
),
)
.emit();
let mut err = tcx.sess.struct_span_err(
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
hir_ty.span,
&format!(
"using {} as const generic parameters is forbidden",
unsupported_type
),
);

if tcx.features().min_const_generics {
err.note("the only supported types are integers, `bool` and `char`")
.note("more complex types are supported with `#[feature(const_generics)]`").emit()
} else {
err.emit();
}
};
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
.is_some()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ error[E0658]: const generics are unstable
LL | trait Trait<const T: ()> {}
| ^
|
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
= help: add `#![feature(const_generics)]` to the crate attributes to enable
= note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
= help: add `#![feature(min_const_generics)]` to the crate attributes to enable

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ error[E0658]: const generics are unstable
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
| ^
|
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
= help: add `#![feature(const_generics)]` to the crate attributes to enable
= note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
= help: add `#![feature(min_const_generics)]` to the crate attributes to enable

error: aborting due to 2 previous errors

Expand Down
Loading