Skip to content

Commit 262a344

Browse files
Add feature gate for non_lifetime_binders
1 parent c528357 commit 262a344

File tree

15 files changed

+155
-75
lines changed

15 files changed

+155
-75
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -294,27 +294,6 @@ impl<'a> AstValidator<'a> {
294294
}
295295
}
296296

297-
fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
298-
// Check only lifetime parameters are present and that the lifetime
299-
// parameters that are present have no bounds.
300-
let non_lt_param_spans: Vec<_> = params
301-
.iter()
302-
.filter_map(|param| match param.kind {
303-
GenericParamKind::Lifetime { .. } => {
304-
if !param.bounds.is_empty() {
305-
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
306-
self.session.emit_err(ForbiddenLifetimeBound { spans });
307-
}
308-
None
309-
}
310-
_ => Some(param.ident.span),
311-
})
312-
.collect();
313-
if !non_lt_param_spans.is_empty() {
314-
self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
315-
}
316-
}
317-
318297
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
319298
self.check_decl_num_args(fn_decl);
320299
self.check_decl_cvaradic_pos(fn_decl);
@@ -745,7 +724,6 @@ impl<'a> AstValidator<'a> {
745724
)
746725
.emit();
747726
});
748-
self.check_late_bound_lifetime_defs(&bfty.generic_params);
749727
if let Extern::Implicit(_) = bfty.ext {
750728
let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
751729
self.maybe_lint_missing_abi(sig_span, ty.id);
@@ -1318,9 +1296,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13181296
for predicate in &generics.where_clause.predicates {
13191297
match predicate {
13201298
WherePredicate::BoundPredicate(bound_pred) => {
1321-
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
1322-
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1323-
13241299
// This is slightly complicated. Our representation for poly-trait-refs contains a single
13251300
// binder and thus we only allow a single level of quantification. However,
13261301
// the syntax of Rust permits quantification in two places in where clauses,
@@ -1396,11 +1371,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13961371
visit::walk_param_bound(self, bound)
13971372
}
13981373

1399-
fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
1400-
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1401-
visit::walk_poly_trait_ref(self, t);
1402-
}
1403-
14041374
fn visit_variant_data(&mut self, s: &'a VariantData) {
14051375
self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
14061376
}
@@ -1437,10 +1407,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14371407
.emit();
14381408
}
14391409

1440-
if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1441-
self.check_late_bound_lifetime_defs(generic_params);
1442-
}
1443-
14441410
if let FnKind::Fn(
14451411
_,
14461412
_,

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use rustc_span::symbol::sym;
1111
use rustc_span::Span;
1212
use rustc_target::spec::abi;
1313

14+
use crate::errors::ForbiddenLifetimeBound;
15+
1416
macro_rules! gate_feature_fn {
1517
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
1618
let (visitor, has_feature, span, name, explain, help) =
@@ -136,6 +138,34 @@ impl<'a> PostExpansionVisitor<'a> {
136138
}
137139
ImplTraitVisitor { vis: self }.visit_ty(ty);
138140
}
141+
142+
fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) {
143+
// Check only lifetime parameters are present and that the lifetime
144+
// parameters that are present have no bounds.
145+
let non_lt_param_spans: Vec<_> = params
146+
.iter()
147+
.filter_map(|param| match param.kind {
148+
ast::GenericParamKind::Lifetime { .. } => None,
149+
_ => Some(param.ident.span),
150+
})
151+
.collect();
152+
// FIXME: gate_feature_post doesn't really handle multispans...
153+
if !non_lt_param_spans.is_empty() && !self.features.non_lifetime_binders {
154+
feature_err(
155+
&self.sess.parse_sess,
156+
sym::non_lifetime_binders,
157+
non_lt_param_spans,
158+
rustc_errors::fluent::ast_passes_forbidden_non_lifetime_param,
159+
)
160+
.emit();
161+
}
162+
for param in params {
163+
if !param.bounds.is_empty() {
164+
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
165+
self.sess.emit_err(ForbiddenLifetimeBound { spans });
166+
}
167+
}
168+
}
139169
}
140170

141171
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
@@ -147,7 +177,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
147177
..
148178
}) = attr_info
149179
{
150-
gate_feature_fn!(self, has_feature, attr.span, *name, descr);
180+
gate_feature_fn!(self, has_feature, attr.span, *name, *descr);
151181
}
152182
// Check unstable flavors of the `#[doc]` attribute.
153183
if attr.has_name(sym::doc) {
@@ -306,6 +336,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
306336
ast::TyKind::BareFn(bare_fn_ty) => {
307337
// Function pointers cannot be `const`
308338
self.check_extern(bare_fn_ty.ext, ast::Const::No);
339+
self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params);
309340
}
310341
ast::TyKind::Never => {
311342
gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental");
@@ -318,6 +349,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
318349
visit::walk_ty(self, ty)
319350
}
320351

352+
fn visit_generics(&mut self, g: &'a ast::Generics) {
353+
for predicate in &g.where_clause.predicates {
354+
match predicate {
355+
ast::WherePredicate::BoundPredicate(bound_pred) => {
356+
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
357+
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
358+
}
359+
_ => {}
360+
}
361+
}
362+
visit::walk_generics(self, g);
363+
}
364+
321365
fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) {
322366
if let ast::FnRetTy::Ty(output_ty) = ret_ty {
323367
if let ast::TyKind::Never = output_ty.kind {
@@ -437,12 +481,21 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
437481
visit::walk_pat(self, pattern)
438482
}
439483

484+
fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
485+
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
486+
visit::walk_poly_trait_ref(self, t);
487+
}
488+
440489
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
441490
if let Some(header) = fn_kind.header() {
442491
// Stability of const fn methods are covered in `visit_assoc_item` below.
443492
self.check_extern(header.ext, header.constness);
444493
}
445494

495+
if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind {
496+
self.check_late_bound_lifetime_defs(generic_params);
497+
}
498+
446499
if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() {
447500
gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
448501
}

compiler/rustc_attr/src/builtin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ pub fn eval_condition(
731731
sess,
732732
sym::cfg_target_compact,
733733
cfg.span,
734-
&"compact `cfg(target(..))` is experimental and subject to change"
734+
"compact `cfg(target(..))` is experimental and subject to change"
735735
).emit();
736736
}
737737

compiler/rustc_feature/src/active.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,8 @@ declare_features! (
473473
(active, no_sanitize, "1.42.0", Some(39699), None),
474474
/// Allows using the `non_exhaustive_omitted_patterns` lint.
475475
(active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
476+
/// Allows `for<T>` binders in where-clauses
477+
(incomplete, non_lifetime_binders, "CURRENT_RUSTC_VERSION", Some(1), None),
476478
/// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
477479
/// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
478480
/// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.

compiler/rustc_session/src/errors.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::cgu_reuse_tracker::CguReuse;
44
use crate::parse::ParseSess;
55
use rustc_ast::token;
66
use rustc_ast::util::literal::LitError;
7-
use rustc_errors::MultiSpan;
7+
use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan};
88
use rustc_macros::Diagnostic;
99
use rustc_span::{Span, Symbol};
1010
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
@@ -27,12 +27,22 @@ pub struct CguNotRecorded<'a> {
2727
pub cgu_name: &'a str,
2828
}
2929

30-
#[derive(Diagnostic)]
31-
#[diag(session_feature_gate_error, code = "E0658")]
32-
pub struct FeatureGateError<'a> {
33-
#[primary_span]
30+
pub struct FeatureGateError {
3431
pub span: MultiSpan,
35-
pub explain: &'a str,
32+
pub explain: DiagnosticMessage,
33+
}
34+
35+
impl<'a, T: EmissionGuarantee> IntoDiagnostic<'a, T> for FeatureGateError {
36+
#[track_caller]
37+
fn into_diagnostic(
38+
self,
39+
handler: &'a rustc_errors::Handler,
40+
) -> rustc_errors::DiagnosticBuilder<'a, T> {
41+
let mut diag = handler.struct_diagnostic(self.explain);
42+
diag.set_span(self.span);
43+
diag.code(error_code!(E0658));
44+
diag
45+
}
3646
}
3747

3848
#[derive(Subdiagnostic)]

compiler/rustc_session/src/parse.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub fn feature_err<'a>(
8888
sess: &'a ParseSess,
8989
feature: Symbol,
9090
span: impl Into<MultiSpan>,
91-
explain: &str,
91+
explain: impl Into<DiagnosticMessage>,
9292
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
9393
feature_err_issue(sess, feature, span, GateIssue::Language, explain)
9494
}
@@ -103,7 +103,7 @@ pub fn feature_err_issue<'a>(
103103
feature: Symbol,
104104
span: impl Into<MultiSpan>,
105105
issue: GateIssue,
106-
explain: &str,
106+
explain: impl Into<DiagnosticMessage>,
107107
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
108108
let span = span.into();
109109

@@ -114,7 +114,7 @@ pub fn feature_err_issue<'a>(
114114
.map(|err| err.cancel());
115115
}
116116

117-
let mut err = sess.create_err(FeatureGateError { span, explain });
117+
let mut err = sess.create_err(FeatureGateError { span, explain: explain.into() });
118118
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
119119
err
120120
}

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,7 @@ symbols! {
10161016
non_ascii_idents,
10171017
non_exhaustive,
10181018
non_exhaustive_omitted_patterns_lint,
1019+
non_lifetime_binders,
10191020
non_modrs_mods,
10201021
nontemporal_store,
10211022
noop_method_borrow,

tests/ui/bounds-lifetime.stderr

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,24 @@ error: lifetime bounds cannot be used in this context
1616
LL | type C = for<'b, 'a: 'b +> fn();
1717
| ^^
1818

19-
error: only lifetime parameters can be used in this context
19+
error[E0658]: only lifetime parameters can be used in this context
2020
--> $DIR/bounds-lifetime.rs:4:18
2121
|
2222
LL | type D = for<'a, T> fn();
2323
| ^
24+
|
25+
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
26+
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
2427

25-
error: only lifetime parameters can be used in this context
28+
error[E0658]: only lifetime parameters can be used in this context
2629
--> $DIR/bounds-lifetime.rs:5:18
2730
|
2831
LL | type E = dyn for<T> Fn();
2932
| ^
33+
|
34+
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
35+
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
3036

3137
error: aborting due to 5 previous errors
3238

39+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
error: only lifetime parameters can be used in this context
1+
error[E0658]: only lifetime parameters can be used in this context
22
--> $DIR/disallow-const.rs:4:15
33
|
44
LL | for<const N: i32> || -> () {};
55
| ^
6+
|
7+
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
8+
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
69

710
error: aborting due to previous error
811

12+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
error: only lifetime parameters can be used in this context
1+
error[E0658]: only lifetime parameters can be used in this context
22
--> $DIR/disallow-ty.rs:4:9
33
|
44
LL | for<T> || -> () {};
55
| ^
6+
|
7+
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
8+
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
69

710
error: aborting due to previous error
811

12+
For more information about this error, try `rustc --explain E0658`.

tests/ui/conditional-compilation/cfg-generic-params.stderr

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,3 @@
1-
error: only lifetime parameters can be used in this context
2-
--> $DIR/cfg-generic-params.rs:7:45
3-
|
4-
LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn();
5-
| ^
6-
7-
error: only lifetime parameters can be used in this context
8-
--> $DIR/cfg-generic-params.rs:11:51
9-
|
10-
LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy;
11-
| ^
12-
13-
error: only lifetime parameters can be used in this context
14-
--> $DIR/cfg-generic-params.rs:15:54
15-
|
16-
LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
17-
| ^
18-
191
error: cannot find attribute `unknown` in this scope
202
--> $DIR/cfg-generic-params.rs:19:29
213
|
@@ -46,5 +28,33 @@ error: cannot find attribute `unknown` in this scope
4628
LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
4729
| ^^^^^^^
4830

31+
error[E0658]: only lifetime parameters can be used in this context
32+
--> $DIR/cfg-generic-params.rs:7:45
33+
|
34+
LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn();
35+
| ^
36+
|
37+
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
38+
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
39+
40+
error[E0658]: only lifetime parameters can be used in this context
41+
--> $DIR/cfg-generic-params.rs:11:51
42+
|
43+
LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy;
44+
| ^
45+
|
46+
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
47+
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
48+
49+
error[E0658]: only lifetime parameters can be used in this context
50+
--> $DIR/cfg-generic-params.rs:15:54
51+
|
52+
LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
53+
| ^
54+
|
55+
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
56+
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
57+
4958
error: aborting due to 8 previous errors
5059

60+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn foo() where for<T> T:, {}
2+
//~^ ERROR only lifetime parameters can be used in this context
3+
4+
fn main() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0658]: only lifetime parameters can be used in this context
2+
--> $DIR/feature-gate-non_lifetime_binders.rs:1:20
3+
|
4+
LL | fn foo() where for<T> T:, {}
5+
| ^
6+
|
7+
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
8+
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)