Add feature gate for non_lifetime_binders

This commit is contained in:
Michael Goulet 2023-02-04 01:59:17 +00:00
parent c5283576ec
commit 262a344d72
15 changed files with 155 additions and 75 deletions

View file

@ -294,27 +294,6 @@ fn check_trait_fn_not_const(&self, constness: Const) {
}
}
fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
// Check only lifetime parameters are present and that the lifetime
// parameters that are present have no bounds.
let non_lt_param_spans: Vec<_> = params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
if !param.bounds.is_empty() {
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
self.session.emit_err(ForbiddenLifetimeBound { spans });
}
None
}
_ => Some(param.ident.span),
})
.collect();
if !non_lt_param_spans.is_empty() {
self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
}
}
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
self.check_decl_num_args(fn_decl);
self.check_decl_cvaradic_pos(fn_decl);
@ -745,7 +724,6 @@ fn visit_ty_common(&mut self, ty: &'a Ty) {
)
.emit();
});
self.check_late_bound_lifetime_defs(&bfty.generic_params);
if let Extern::Implicit(_) = bfty.ext {
let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
self.maybe_lint_missing_abi(sig_span, ty.id);
@ -1318,9 +1296,6 @@ fn visit_generics(&mut self, generics: &'a Generics) {
for predicate in &generics.where_clause.predicates {
match predicate {
WherePredicate::BoundPredicate(bound_pred) => {
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
// This is slightly complicated. Our representation for poly-trait-refs contains a single
// binder and thus we only allow a single level of quantification. However,
// the syntax of Rust permits quantification in two places in where clauses,
@ -1396,11 +1371,6 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
visit::walk_param_bound(self, bound)
}
fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
visit::walk_poly_trait_ref(self, t);
}
fn visit_variant_data(&mut self, s: &'a VariantData) {
self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
}
@ -1437,10 +1407,6 @@ fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
.emit();
}
if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
self.check_late_bound_lifetime_defs(generic_params);
}
if let FnKind::Fn(
_,
_,

View file

@ -11,6 +11,8 @@
use rustc_span::Span;
use rustc_target::spec::abi;
use crate::errors::ForbiddenLifetimeBound;
macro_rules! gate_feature_fn {
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
let (visitor, has_feature, span, name, explain, help) =
@ -136,6 +138,34 @@ fn visit_ty(&mut self, ty: &ast::Ty) {
}
ImplTraitVisitor { vis: self }.visit_ty(ty);
}
fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) {
// Check only lifetime parameters are present and that the lifetime
// parameters that are present have no bounds.
let non_lt_param_spans: Vec<_> = params
.iter()
.filter_map(|param| match param.kind {
ast::GenericParamKind::Lifetime { .. } => None,
_ => Some(param.ident.span),
})
.collect();
// FIXME: gate_feature_post doesn't really handle multispans...
if !non_lt_param_spans.is_empty() && !self.features.non_lifetime_binders {
feature_err(
&self.sess.parse_sess,
sym::non_lifetime_binders,
non_lt_param_spans,
rustc_errors::fluent::ast_passes_forbidden_non_lifetime_param,
)
.emit();
}
for param in params {
if !param.bounds.is_empty() {
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
self.sess.emit_err(ForbiddenLifetimeBound { spans });
}
}
}
}
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
@ -147,7 +177,7 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
..
}) = attr_info
{
gate_feature_fn!(self, has_feature, attr.span, *name, descr);
gate_feature_fn!(self, has_feature, attr.span, *name, *descr);
}
// Check unstable flavors of the `#[doc]` attribute.
if attr.has_name(sym::doc) {
@ -306,6 +336,7 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) {
ast::TyKind::BareFn(bare_fn_ty) => {
// Function pointers cannot be `const`
self.check_extern(bare_fn_ty.ext, ast::Const::No);
self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params);
}
ast::TyKind::Never => {
gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental");
@ -318,6 +349,19 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) {
visit::walk_ty(self, ty)
}
fn visit_generics(&mut self, g: &'a ast::Generics) {
for predicate in &g.where_clause.predicates {
match predicate {
ast::WherePredicate::BoundPredicate(bound_pred) => {
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
}
_ => {}
}
}
visit::walk_generics(self, g);
}
fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) {
if let ast::FnRetTy::Ty(output_ty) = ret_ty {
if let ast::TyKind::Never = output_ty.kind {
@ -437,12 +481,21 @@ fn visit_pat(&mut self, pattern: &'a ast::Pat) {
visit::walk_pat(self, pattern)
}
fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
visit::walk_poly_trait_ref(self, t);
}
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
if let Some(header) = fn_kind.header() {
// Stability of const fn methods are covered in `visit_assoc_item` below.
self.check_extern(header.ext, header.constness);
}
if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind {
self.check_late_bound_lifetime_defs(generic_params);
}
if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() {
gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
}

View file

@ -731,7 +731,7 @@ pub fn eval_condition(
sess,
sym::cfg_target_compact,
cfg.span,
&"compact `cfg(target(..))` is experimental and subject to change"
"compact `cfg(target(..))` is experimental and subject to change"
).emit();
}

View file

@ -473,6 +473,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
(active, no_sanitize, "1.42.0", Some(39699), None),
/// Allows using the `non_exhaustive_omitted_patterns` lint.
(active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
/// Allows `for<T>` binders in where-clauses
(incomplete, non_lifetime_binders, "CURRENT_RUSTC_VERSION", Some(1), None),
/// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
/// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
/// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.

View file

@ -4,7 +4,7 @@
use crate::parse::ParseSess;
use rustc_ast::token;
use rustc_ast::util::literal::LitError;
use rustc_errors::MultiSpan;
use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan};
use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol};
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
@ -27,12 +27,22 @@ pub struct CguNotRecorded<'a> {
pub cgu_name: &'a str,
}
#[derive(Diagnostic)]
#[diag(session_feature_gate_error, code = "E0658")]
pub struct FeatureGateError<'a> {
#[primary_span]
pub struct FeatureGateError {
pub span: MultiSpan,
pub explain: &'a str,
pub explain: DiagnosticMessage,
}
impl<'a, T: EmissionGuarantee> IntoDiagnostic<'a, T> for FeatureGateError {
#[track_caller]
fn into_diagnostic(
self,
handler: &'a rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'a, T> {
let mut diag = handler.struct_diagnostic(self.explain);
diag.set_span(self.span);
diag.code(error_code!(E0658));
diag
}
}
#[derive(Subdiagnostic)]

View file

@ -88,7 +88,7 @@ pub fn feature_err<'a>(
sess: &'a ParseSess,
feature: Symbol,
span: impl Into<MultiSpan>,
explain: &str,
explain: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
feature_err_issue(sess, feature, span, GateIssue::Language, explain)
}
@ -103,7 +103,7 @@ pub fn feature_err_issue<'a>(
feature: Symbol,
span: impl Into<MultiSpan>,
issue: GateIssue,
explain: &str,
explain: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let span = span.into();
@ -114,7 +114,7 @@ pub fn feature_err_issue<'a>(
.map(|err| err.cancel());
}
let mut err = sess.create_err(FeatureGateError { span, explain });
let mut err = sess.create_err(FeatureGateError { span, explain: explain.into() });
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
err
}

View file

@ -1016,6 +1016,7 @@
non_ascii_idents,
non_exhaustive,
non_exhaustive_omitted_patterns_lint,
non_lifetime_binders,
non_modrs_mods,
nontemporal_store,
noop_method_borrow,

View file

@ -16,17 +16,24 @@ error: lifetime bounds cannot be used in this context
LL | type C = for<'b, 'a: 'b +> fn();
| ^^
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/bounds-lifetime.rs:4:18
|
LL | type D = for<'a, T> fn();
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/bounds-lifetime.rs:5:18
|
LL | type E = dyn for<T> Fn();
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,8 +1,12 @@
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/disallow-const.rs:4:15
|
LL | for<const N: i32> || -> () {};
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,8 +1,12 @@
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/disallow-ty.rs:4:9
|
LL | for<T> || -> () {};
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,21 +1,3 @@
error: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:7:45
|
LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn();
| ^
error: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:11:51
|
LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy;
| ^
error: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:15:54
|
LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
| ^
error: cannot find attribute `unknown` in this scope
--> $DIR/cfg-generic-params.rs:19:29
|
@ -46,5 +28,33 @@ error: cannot find attribute `unknown` in this scope
LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
| ^^^^^^^
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:7:45
|
LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn();
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:11:51
|
LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy;
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:15:54
|
LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,4 @@
fn foo() where for<T> T:, {}
//~^ ERROR only lifetime parameters can be used in this context
fn main() {}

View file

@ -0,0 +1,12 @@
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/feature-gate-non_lifetime_binders.rs:1:20
|
LL | fn foo() where for<T> T:, {}
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,14 +1,21 @@
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/hrtb-wrong-kind.rs:1:18
|
LL | fn a() where for<T> T: Copy {}
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/hrtb-wrong-kind.rs:4:24
|
LL | fn b() where for<const C: usize> [(); C]: Copy {}
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -88,12 +88,6 @@ error: expected identifier, found `>`
LL | type QuiteBroken = fn<const>();
| ^ expected identifier
error: lifetime bounds cannot be used in this context
--> $DIR/recover-fn-ptr-with-generics.rs:22:26
|
LL | let _: extern fn<'a: 'static>();
| ^^^^^^^
error[E0412]: cannot find type `T` in this scope
--> $DIR/recover-fn-ptr-with-generics.rs:5:27
|
@ -106,6 +100,12 @@ error[E0412]: cannot find type `T` in this scope
LL | type Identity = fn<T>(T) -> T;
| ^ not found in this scope
error: lifetime bounds cannot be used in this context
--> $DIR/recover-fn-ptr-with-generics.rs:22:26
|
LL | let _: extern fn<'a: 'static>();
| ^^^^^^^
error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0412`.