Auto merge of #84299 - lcnr:const-generics-defaults-name-res, r=varkor

various const parameter defaults improvements

Actually resolve names in const parameter defaults, fixing `struct Foo<const N: usize = { usize::MAX }>`.

---
Split generic parameter ban rib for types and consts, allowing
```rust
#![feature(const_generics_defaults)]
struct Q;
struct Foo<T = Q, const Q: usize = 3>(T);
```

---
Remove the type/const ordering restriction if `const_generics_defaults` is active, even if `const_generics` is not. allowing us to stabilize and test const param defaults separately.

---
Check well formedness of const parameter defaults, eagerly emitting an error for `struct Foo<const N: usize = { 0 - 1 }>`

---
Do not forbid const parameters in param defaults, allowing `struct Foo<const N: usize, T = [u8; N]>(T)` and `struct Foo<const N: usize, const M: usize = N>`. Note that this should not change anything which is stabilized, as on stable, type parameters must be in front of const parameters, which means that type parameter defaults are only allowed if no const parameters exist.

We still forbid generic parameters inside of const param types.

r? `@varkor` `@petrochenkov`
This commit is contained in:
bors 2021-04-25 14:00:49 +00:00
commit 58bdb08947
45 changed files with 385 additions and 217 deletions

View File

@ -754,7 +754,7 @@ fn validate_generic_param_order(
GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
let ty = pprust::ty_to_string(ty);
let unordered = sess.features_untracked().const_generics;
let unordered = sess.features_untracked().unordered_const_ty_params();
(ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty)))
}
};

View File

@ -63,6 +63,10 @@ macro_rules! declare_features {
_ => panic!("`{}` was not listed in `declare_features`", feature),
}
}
pub fn unordered_const_ty_params(&self) -> bool {
self.const_generics || self.const_generics_defaults
}
}
};
}

View File

@ -296,7 +296,9 @@ impl GenericArg<'_> {
match self {
GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime,
GenericArg::Type(_) => ast::ParamKindOrd::Type,
GenericArg::Const(_) => ast::ParamKindOrd::Const { unordered: feats.const_generics },
GenericArg::Const(_) => {
ast::ParamKindOrd::Const { unordered: feats.unordered_const_ty_params() }
}
}
}
}

View File

@ -36,7 +36,7 @@ impl GenericParamDefKind {
GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type,
GenericParamDefKind::Const { .. } => {
ast::ParamKindOrd::Const { unordered: tcx.features().const_generics }
ast::ParamKindOrd::Const { unordered: tcx.features().unordered_const_ty_params() }
}
}
}

View File

@ -472,17 +472,6 @@ impl<'a> Resolver<'a> {
);
err
}
ResolutionError::ParamInAnonConstInTyDefault(name) => {
let mut err = self.session.struct_span_err(
span,
"constant values inside of type parameter defaults must not depend on generic parameters",
);
err.span_label(
span,
format!("the anonymous constant must not depend on the parameter `{}`", name),
);
err
}
ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
let mut err = self.session.struct_span_err(
span,

View File

@ -555,18 +555,23 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// provide previous type parameters as they're built. We
// put all the parameters on the ban list and then remove
// them one by one as they are processed and become available.
let mut default_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
let mut found_default = false;
default_ban_rib.bindings.extend(generics.params.iter().filter_map(
|param| match param.kind {
GenericParamKind::Type { default: Some(_), .. }
| GenericParamKind::Const { default: Some(_), .. } => {
found_default = true;
Some((Ident::with_dummy_span(param.ident.name), Res::Err))
let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
for param in generics.params.iter() {
match param.kind {
GenericParamKind::Type { .. } => {
forward_ty_ban_rib
.bindings
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
}
_ => None,
},
));
GenericParamKind::Const { .. } => {
forward_const_ban_rib
.bindings
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
}
GenericParamKind::Lifetime => {}
}
}
// rust-lang/rust#61631: The type `Self` is essentially
// another type parameter. For ADTs, we consider it
@ -579,7 +584,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// such as in the case of `trait Add<Rhs = Self>`.)
if self.diagnostic_metadata.current_self_item.is_some() {
// (`Some` if + only if we are in ADT's generics.)
default_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
}
for param in &generics.params {
@ -591,32 +596,38 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
}
if let Some(ref ty) = default {
self.ribs[TypeNS].push(default_ban_rib);
self.with_rib(ValueNS, ForwardGenericParamBanRibKind, |this| {
// HACK: We use an empty `ForwardGenericParamBanRibKind` here which
// is only used to forbid the use of const parameters inside of
// type defaults.
//
// While the rib name doesn't really fit here, it does allow us to use the same
// code for both const and type parameters.
this.visit_ty(ty);
});
default_ban_rib = self.ribs[TypeNS].pop().unwrap();
self.ribs[TypeNS].push(forward_ty_ban_rib);
self.ribs[ValueNS].push(forward_const_ban_rib);
self.visit_ty(ty);
forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
}
// Allow all following defaults to refer to this type parameter.
default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
forward_ty_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
}
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
// FIXME(const_generics_defaults): handle `default` value here
for bound in &param.bounds {
self.visit_param_bound(bound);
}
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
// Const parameters can't have param bounds.
assert!(param.bounds.is_empty());
self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
self.visit_ty(ty);
self.ribs[TypeNS].pop().unwrap();
self.ribs[ValueNS].pop().unwrap();
if let Some(ref expr) = default {
self.ribs[TypeNS].push(forward_ty_ban_rib);
self.ribs[ValueNS].push(forward_const_ban_rib);
self.visit_anon_const(expr);
forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
}
// Allow all following defaults to refer to this const parameter.
forward_const_ban_rib
.bindings
.remove(&Ident::with_dummy_span(param.ident.name));
}
}
}

View File

@ -239,8 +239,6 @@ enum ResolutionError<'a> {
ForwardDeclaredTyParam, // FIXME(const_generics_defaults)
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
ParamInTyOfConstParam(Symbol),
/// constant values inside of type parameter defaults must not depend on generic parameters.
ParamInAnonConstInTyDefault(Symbol),
/// generic parameters must not be used inside const evaluations.
///
/// This error is only emitted when using `min_const_generics`.
@ -2672,26 +2670,18 @@ impl<'a> Resolver<'a> {
}
}
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
let mut in_ty_param_default = false;
for rib in ribs {
let has_generic_params = match rib.kind {
let has_generic_params: HasGenericParams = match rib.kind {
NormalRibKind
| ClosureOrAsyncRibKind
| AssocItemRibKind
| ModuleRibKind(..)
| MacroDefinition(..) => {
| MacroDefinition(..)
| ForwardGenericParamBanRibKind => {
// Nothing to do. Continue.
continue;
}
// We only forbid constant items if we are inside of type defaults,
// for example `struct Foo<T, U = [u8; std::mem::size_of::<T>()]>`
ForwardGenericParamBanRibKind => {
// FIXME(const_generic_defaults): we may need to distinguish between
// being in type parameter defaults and const parameter defaults
in_ty_param_default = true;
continue;
}
ConstantItemRibKind(trivial, _) => {
let features = self.session.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
@ -2720,19 +2710,7 @@ impl<'a> Resolver<'a> {
}
}
if in_ty_param_default {
if record_used {
self.report_error(
span,
ResolutionError::ParamInAnonConstInTyDefault(
rib_ident.name,
),
);
}
return Res::Err;
} else {
continue;
}
continue;
}
// This was an attempt to use a type parameter outside its scope.
@ -2770,23 +2748,15 @@ impl<'a> Resolver<'a> {
ribs.next();
}
let mut in_ty_param_default = false;
for rib in ribs {
let has_generic_params = match rib.kind {
NormalRibKind
| ClosureOrAsyncRibKind
| AssocItemRibKind
| ModuleRibKind(..)
| MacroDefinition(..) => continue,
| MacroDefinition(..)
| ForwardGenericParamBanRibKind => continue,
// We only forbid constant items if we are inside of type defaults,
// for example `struct Foo<T, U = [u8; std::mem::size_of::<T>()]>`
ForwardGenericParamBanRibKind => {
// FIXME(const_generic_defaults): we may need to distinguish between
// being in type parameter defaults and const parameter defaults
in_ty_param_default = true;
continue;
}
ConstantItemRibKind(trivial, _) => {
let features = self.session.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
@ -2808,19 +2778,7 @@ impl<'a> Resolver<'a> {
return Res::Err;
}
if in_ty_param_default {
if record_used {
self.report_error(
span,
ResolutionError::ParamInAnonConstInTyDefault(
rib_ident.name,
),
);
}
return Res::Err;
} else {
continue;
}
continue;
}
ItemRibKind(has_generic_params) => has_generic_params,

View File

@ -286,7 +286,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ParamKindOrd::Const {
unordered: tcx
.features()
.const_generics,
.unordered_const_ty_params(),
}
}
},
@ -309,7 +309,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
GenericArg::Type(_) => ParamKindOrd::Type,
GenericArg::Const(_) => ParamKindOrd::Const {
unordered: tcx.features().const_generics,
unordered: tcx
.features()
.unordered_const_ty_params(),
},
}),
Some(&format!(

View File

@ -513,7 +513,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
GenericParamDefKind::Const { has_default } => {
let ty = tcx.at(self.span).type_of(param.def_id);
if !infer_args && has_default {
tcx.const_param_default(param.def_id).into()
tcx.const_param_default(param.def_id)
.subst_spanned(tcx, substs.unwrap(), Some(self.span))
.into()
} else {
if infer_args {
self.astconv.ct_infer(ty, Some(param), self.span).into()

View File

@ -1446,7 +1446,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
GenericParamDefKind::Const { has_default, .. } => {
if !infer_args && has_default {
tcx.const_param_default(param.def_id).into()
tcx.const_param_default(param.def_id)
.subst_spanned(tcx, substs.unwrap(), Some(self.span))
.into()
} else {
self.fcx.var_for_def(self.span, param)
}

View File

@ -728,20 +728,36 @@ fn check_where_clauses<'tcx, 'fcx>(
//
// Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
for param in &generics.params {
if let GenericParamDefKind::Type { .. } = param.kind {
if is_our_default(&param) {
let ty = fcx.tcx.type_of(param.def_id);
// Ignore dependent defaults -- that is, where the default of one type
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
// be sure if it will error or not as user might always specify the other.
if !ty.needs_subst() {
match param.kind {
GenericParamDefKind::Type { .. } => {
if is_our_default(&param) {
let ty = fcx.tcx.type_of(param.def_id);
// Ignore dependent defaults -- that is, where the default of one type
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
// be sure if it will error or not as user might always specify the other.
if !ty.needs_subst() {
fcx.register_wf_obligation(
ty.into(),
fcx.tcx.def_span(param.def_id),
ObligationCauseCode::MiscObligation,
);
}
}
}
GenericParamDefKind::Const { .. } => {
// FIXME(const_generics_defaults): Figure out if this
// is the behavior we want, see the comment further below.
if is_our_default(&param) {
let default_ct = tcx.const_param_default(param.def_id);
fcx.register_wf_obligation(
ty.into(),
default_ct.into(),
fcx.tcx.def_span(param.def_id),
ObligationCauseCode::MiscObligation,
);
}
}
// Doesn't have defaults.
GenericParamDefKind::Lifetime => {}
}
}
@ -774,14 +790,25 @@ fn check_where_clauses<'tcx, 'fcx>(
fcx.tcx.mk_param_from_def(param)
}
GenericParamDefKind::Const { .. } => {
// FIXME(const_generics_defaults): I(@lcnr) feel like always
// using the const parameter is the right choice here, even
// if it needs substs.
//
// Before stabilizing this we probably want to get some tests
// where this makes a difference and figure out what's the exact
// behavior we want here.
// If the param has a default, ...
if is_our_default(param) {
let default_ct = tcx.const_param_default(param.def_id);
// Const params currently have to be concrete.
assert!(!default_ct.needs_subst());
default_ct.into()
} else {
fcx.tcx.mk_param_from_def(param)
// ... and it's not a dependent default, ...
if !default_ct.needs_subst() {
// ... then substitute it with the default.
return default_ct.into();
}
}
fcx.tcx.mk_param_from_def(param)
}
}
});

View File

@ -1327,13 +1327,13 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
}
}
struct AnonConstInParamListDetector {
in_param_list: bool,
found_anon_const_in_list: bool,
struct AnonConstInParamTyDetector {
in_param_ty: bool,
found_anon_const_in_param_ty: bool,
ct: HirId,
}
impl<'v> Visitor<'v> for AnonConstInParamListDetector {
impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
type Map = intravisit::ErasedMap<'v>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@ -1341,15 +1341,17 @@ impl<'v> Visitor<'v> for AnonConstInParamListDetector {
}
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
let prev = self.in_param_list;
self.in_param_list = true;
intravisit::walk_generic_param(self, p);
self.in_param_list = prev;
if let GenericParamKind::Const { ref ty, default: _ } = p.kind {
let prev = self.in_param_ty;
self.in_param_ty = true;
self.visit_ty(ty);
self.in_param_ty = prev;
}
}
fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
if self.in_param_list && self.ct == c.hir_id {
self.found_anon_const_in_list = true;
if self.in_param_ty && self.ct == c.hir_id {
self.found_anon_const_in_param_ty = true;
} else {
intravisit::walk_anon_const(self, c)
}
@ -1377,27 +1379,24 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
let parent_id = tcx.hir().get_parent_item(hir_id);
let parent_def_id = tcx.hir().local_def_id(parent_id);
let mut in_param_list = false;
let mut in_param_ty = false;
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
if let Some(generics) = node.generics() {
let mut visitor = AnonConstInParamListDetector {
in_param_list: false,
found_anon_const_in_list: false,
let mut visitor = AnonConstInParamTyDetector {
in_param_ty: false,
found_anon_const_in_param_ty: false,
ct: hir_id,
};
visitor.visit_generics(generics);
in_param_list = visitor.found_anon_const_in_list;
in_param_ty = visitor.found_anon_const_in_param_ty;
break;
}
}
if in_param_list {
if in_param_ty {
// We do not allow generic parameters in anon consts if we are inside
// of a param list.
//
// This affects both default type bindings, e.g. `struct<T, U = [u8; std::mem::size_of::<T>()]>(T, U)`,
// and the types of const parameters, e.g. `struct V<const N: usize, const M: [u8; N]>();`.
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.lazy_normalization() {
// HACK(eddyb) this provides the correct generics when

View File

@ -1,4 +1,4 @@
#![feature(const_generics)]
#![cfg_attr(full, feature(const_generics))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]

View File

@ -0,0 +1,18 @@
error: constant expression depends on a generic parameter
--> $DIR/complex-generic-default-expr.rs:6:34
|
LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
| ^
|
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
--> $DIR/complex-generic-default-expr.rs:10:21
|
LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
| ^^^^^^^^^
|
= note: this may fail depending on what value the parameter takes
error: aborting due to 2 previous errors

View File

@ -0,0 +1,20 @@
error: generic parameters may not be used in const operations
--> $DIR/complex-generic-default-expr.rs:6:47
|
LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
--> $DIR/complex-generic-default-expr.rs:10:62
|
LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
| ^ cannot perform const operation using `T`
|
= note: type parameters may not be used in const expressions
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to 2 previous errors

View File

@ -0,0 +1,14 @@
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
struct Foo<const N: usize, const M: usize = { N + 1 }>;
//[full]~^ ERROR constant expression depends on a generic parameter
//[min]~^^ ERROR generic parameters may not be used in const operations
struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
//[full]~^ ERROR constant expression depends on a generic parameter
//[min]~^^ ERROR generic parameters may not be used in const operations
fn main() {}

View File

@ -1,6 +1,6 @@
// run-pass
#![feature(const_generics)]
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]

View File

@ -0,0 +1,23 @@
// run-pass
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
struct Foo<const N: usize, const M: usize = N>([u8; N], [u8; M]);
fn foo<const N: usize>() -> Foo<N> {
let x = [0; N];
Foo(x, x)
}
// To check that we actually apply the correct substs for const param defaults.
fn concrete_foo() -> Foo<13> {
Foo(Default::default(), Default::default())
}
fn main() {
let val = foo::<13>();
assert_eq!(val.0, val.1);
let val = concrete_foo();
assert_eq!(val.0, val.1);
}

View File

@ -0,0 +1,14 @@
// run-pass
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
struct Foo<const N: usize, T = [u8; N]>(T);
impl<const N: usize> Foo<N> {
fn new() -> Self {
Foo([0; N])
}
}
fn main() {
assert_eq!(Foo::new().0, [0; 10]);
}

View File

@ -0,0 +1,8 @@
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
--> $DIR/default-on-impl.rs:8:12
|
LL | impl<const N: usize = 1> Foo<N> {}
| ^
error: aborting due to previous error

View File

@ -0,0 +1,8 @@
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
--> $DIR/default-on-impl.rs:8:12
|
LL | impl<const N: usize = 1> Foo<N> {}
| ^
error: aborting due to previous error

View File

@ -0,0 +1,11 @@
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
struct Foo<const N: usize>;
impl<const N: usize = 1> Foo<N> {}
//~^ ERROR defaults for const parameters are only allowed
fn main() {}

View File

@ -0,0 +1,5 @@
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
struct Foo<const N: u8 = { 255 + 1 }>;
//~^ ERROR evaluation of constant value failed
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0080]: evaluation of constant value failed
--> $DIR/default-param-wf-concrete.rs:3:28
|
LL | struct Foo<const N: u8 = { 255 + 1 }>;
| ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
error: aborting due to previous error
For more information about this error, try `rustc --explain E0080`.

View File

@ -1,5 +1,7 @@
// aux-build:const_defaulty.rs
// check-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]

View File

@ -1,5 +1,5 @@
error: lifetime parameters must be declared prior to const parameters
--> $DIR/intermixed-lifetime.rs:6:28
--> $DIR/intermixed-lifetime.rs:7:28
|
LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
| -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`

View File

@ -1,26 +1,14 @@
error: lifetime parameters must be declared prior to const parameters
--> $DIR/intermixed-lifetime.rs:6:28
--> $DIR/intermixed-lifetime.rs:7:28
|
LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
| -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T = u32, const N: usize>`
| -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const N: usize, T = u32>`
error: type parameters must be declared prior to const parameters
--> $DIR/intermixed-lifetime.rs:6:32
|
LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
| ---------------------^------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T = u32, const N: usize>`
error: lifetime parameters must be declared prior to const parameters
error: lifetime parameters must be declared prior to type parameters
--> $DIR/intermixed-lifetime.rs:10:37
|
LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
| --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T = u32, const N: usize>`
| --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const N: usize, T = u32>`
error: type parameters must be declared prior to const parameters
--> $DIR/intermixed-lifetime.rs:10:28
|
LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
| -----------------^----------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T = u32, const N: usize>`
error: aborting due to 4 previous errors
error: aborting due to 2 previous errors

View File

@ -1,15 +1,13 @@
// revisions: full min
// Checks that lifetimes cannot be interspersed between consts and types.
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
//~^ Error lifetime parameters must be declared prior to const parameters
//[min]~^^ Error type parameters must be declared prior to const parameters
struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
//[full]~^ Error lifetime parameters must be declared prior to type parameters
//[min]~^^ Error type parameters must be declared prior to const parameters
//[min]~| Error lifetime parameters must be declared prior to const parameters
//~^ Error lifetime parameters must be declared prior to type parameters
fn main() {}

View File

@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/mismatch.rs:11:28
--> $DIR/mismatch.rs:12:28
|
LL | let e: Example::<13> = ();
| ------------- ^^ expected struct `Example`, found `()`
@ -7,7 +7,7 @@ LL | let e: Example::<13> = ();
| expected due to this
error[E0308]: mismatched types
--> $DIR/mismatch.rs:13:34
--> $DIR/mismatch.rs:14:34
|
LL | let e: Example2::<u32, 13> = ();
| ------------------- ^^ expected struct `Example2`, found `()`
@ -18,7 +18,7 @@ LL | let e: Example2::<u32, 13> = ();
found unit type `()`
error[E0308]: mismatched types
--> $DIR/mismatch.rs:15:34
--> $DIR/mismatch.rs:16:34
|
LL | let e: Example3::<13, u32> = ();
| ------------------- ^^ expected struct `Example3`, found `()`
@ -29,7 +29,7 @@ LL | let e: Example3::<13, u32> = ();
found unit type `()`
error[E0308]: mismatched types
--> $DIR/mismatch.rs:17:28
--> $DIR/mismatch.rs:18:28
|
LL | let e: Example3::<7> = ();
| ------------- ^^ expected struct `Example3`, found `()`
@ -40,7 +40,7 @@ LL | let e: Example3::<7> = ();
found unit type `()`
error[E0308]: mismatched types
--> $DIR/mismatch.rs:21:28
--> $DIR/mismatch.rs:22:28
|
LL | let e: Example4::<7> = ();
| ------------- ^^ expected struct `Example4`, found `()`

View File

@ -0,0 +1,52 @@
error[E0308]: mismatched types
--> $DIR/mismatch.rs:12:28
|
LL | let e: Example::<13> = ();
| ------------- ^^ expected struct `Example`, found `()`
| |
| expected due to this
error[E0308]: mismatched types
--> $DIR/mismatch.rs:14:34
|
LL | let e: Example2::<u32, 13> = ();
| ------------------- ^^ expected struct `Example2`, found `()`
| |
| expected due to this
|
= note: expected struct `Example2`
found unit type `()`
error[E0308]: mismatched types
--> $DIR/mismatch.rs:16:34
|
LL | let e: Example3::<13, u32> = ();
| ------------------- ^^ expected struct `Example3`, found `()`
| |
| expected due to this
|
= note: expected struct `Example3`
found unit type `()`
error[E0308]: mismatched types
--> $DIR/mismatch.rs:18:28
|
LL | let e: Example3::<7> = ();
| ------------- ^^ expected struct `Example3`, found `()`
| |
| expected due to this
|
= note: expected struct `Example3<7_usize>`
found unit type `()`
error[E0308]: mismatched types
--> $DIR/mismatch.rs:22:28
|
LL | let e: Example4::<7> = ();
| ------------- ^^ expected struct `Example4`, found `()`
| |
| expected due to this
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -1,4 +1,5 @@
#![feature(const_generics)]
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]

View File

@ -10,4 +10,4 @@ trait Foo<const KIND: bool = true> {}
fn foo<const SIZE: usize = 5>() {}
struct Range<const FROM: usize = 0, const LEN: usize = 0, const TO: usize = {FROM + LEN}>;
struct Range<const FROM: usize = 0, const LEN: usize = 0, const TO: usize = FROM>;

View File

@ -17,4 +17,4 @@ trait Foo<const KIND : bool = true> { }
fn foo<const SIZE : usize = 5>() { }
struct Range<const FROM : usize = 0, const LEN : usize = 0, const TO : usize =
{ FROM + LEN }>;
FROM>;

View File

@ -6,7 +6,7 @@
#![allow(incomplete_features)]
#[repr(C)]
pub struct Loaf<T: Sized, const N: usize = 1usize> {
pub struct Loaf<T: Sized, const N: usize = 1> {
head: [T; N],
slice: [T],
}

View File

@ -1,8 +0,0 @@
error: type parameters must be declared prior to const parameters
--> $DIR/simple-defaults.rs:8:40
|
LL | struct FixedOutput<'a, const N: usize, T=u32> {
| ---------------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T = u32, const N: usize>`
error: aborting due to previous error

View File

@ -1,12 +1,12 @@
// [full] run-pass
// revisions: min full
// Checks some basic test cases for defaults.
// run-pass
// Checks that type param defaults are allowed after const params.
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
#![allow(dead_code)]
struct FixedOutput<'a, const N: usize, T=u32> {
//[min]~^ ERROR type parameters must be declared prior to const parameters
out: &'a [T; N],
}

View File

@ -0,0 +1,19 @@
// check-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
struct N;
struct Foo<const N: usize = 1, T = N>(T);
impl Foo {
fn new() -> Self {
Foo(N)
}
}
fn main() {
let Foo::<1, N>(N) = Foo::new();
}

View File

@ -1,19 +1,8 @@
error: generic parameters with a default must be trailing
--> $DIR/wrong-order.rs:4:10
--> $DIR/wrong-order.rs:6:10
|
LL | struct A<T = u32, const N: usize> {
| ^
|
= note: using type defaults and const parameters in the same parameter list is currently not permitted
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/wrong-order.rs:2:27
|
LL | #![cfg_attr(full, feature(const_generics))]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
error: aborting due to previous error; 1 warning emitted
error: aborting due to previous error

View File

@ -1,10 +1,8 @@
error: generic parameters with a default must be trailing
--> $DIR/wrong-order.rs:4:10
--> $DIR/wrong-order.rs:6:10
|
LL | struct A<T = u32, const N: usize> {
| ^
|
= note: using type defaults and const parameters in the same parameter list is currently not permitted
error: aborting due to previous error

View File

@ -1,5 +1,7 @@
// revisions: full min
#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
#![cfg_attr(full, feature(const_generics))]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
struct A<T = u32, const N: usize> {
//~^ ERROR generic parameters with a default must be trailing

View File

@ -1,22 +1,17 @@
error: generic parameters with a default must be trailing
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:12
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:12
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^
|
= note: using type defaults and const parameters in the same parameter list is currently not permitted
error: constant values inside of type parameter defaults must not depend on generic parameters
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:6:44
|
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
| ^ the anonymous constant must not depend on the parameter `T`
error: constant values inside of type parameter defaults must not depend on generic parameters
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:21
error[E0128]: generic parameters with a default cannot use forward declared identifiers
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:21
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^ the anonymous constant must not depend on the parameter `N`
| ^ defaulted generic parameters cannot be forward declared
error: aborting due to 3 previous errors
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0128`.

View File

@ -1,5 +1,5 @@
error: generic parameters with a default must be trailing
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:12
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:12
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^
@ -7,7 +7,7 @@ LL | struct Bar<T = [u8; N], const N: usize>(T);
= note: using type defaults and const parameters in the same parameter list is currently not permitted
error: generic parameters may not be used in const operations
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:6:44
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:5:44
|
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
| ^ cannot perform const operation using `T`
@ -15,11 +15,12 @@ LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
= note: type parameters may not be used in const expressions
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: constant values inside of type parameter defaults must not depend on generic parameters
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:21
error[E0128]: generic parameters with a default cannot use forward declared identifiers
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:21
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^ the anonymous constant must not depend on the parameter `N`
| ^ defaulted generic parameters cannot be forward declared
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0128`.

View File

@ -1,15 +1,12 @@
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
//[full]~^ ERROR constant values inside of type parameter defaults
//[min]~^^ ERROR generic parameters may not be used in const operations
//[min]~^ ERROR generic parameters may not be used in const operations
// FIXME(const_generics_defaults): We still don't know how to deal with type defaults.
struct Bar<T = [u8; N], const N: usize>(T);
//~^ ERROR constant values inside of type parameter defaults
//~^ ERROR generic parameters with a default cannot use forward declared identifiers
//~| ERROR generic parameters with a default
fn main() {}

View File

@ -5,5 +5,6 @@ struct Vec<A = Heap, T>(A, T);
struct Foo<A, B = Vec<C>, C>(A, B, C);
//~^ ERROR generic parameters with a default must be trailing
//~| ERROR generic parameters with a default cannot use
fn main() {}

View File

@ -10,5 +10,12 @@ error: generic parameters with a default must be trailing
LL | struct Foo<A, B = Vec<C>, C>(A, B, C);
| ^
error: aborting due to 2 previous errors
error[E0128]: generic parameters with a default cannot use forward declared identifiers
--> $DIR/generic-non-trailing-defaults.rs:6:23
|
LL | struct Foo<A, B = Vec<C>, C>(A, B, C);
| ^ defaulted generic parameters cannot be forward declared
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0128`.