Skip to content

Commit 98e4017

Browse files
committed
Temporarily emulate the (accidentally) omitted recursion during impl Trait check.
Note that the two previous visitors were omitting slightly different recursive calls, so I need two flags to properly emulate them.
1 parent b58a006 commit 98e4017

File tree

3 files changed

+84
-15
lines changed

3 files changed

+84
-15
lines changed

src/librustc/lint/builtin.rs

+14
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,12 @@ declare_lint! {
386386
"ambiguous associated items"
387387
}
388388

389+
declare_lint! {
390+
pub NESTED_IMPL_TRAIT,
391+
Warn,
392+
"nested occurrence of `impl Trait` type"
393+
}
394+
389395
/// Does nothing as a lint pass, but registers some `Lint`s
390396
/// that are used by other parts of the compiler.
391397
#[derive(Copy, Clone)]
@@ -457,6 +463,7 @@ impl LintPass for HardwiredLints {
457463
parser::ILL_FORMED_ATTRIBUTE_INPUT,
458464
DEPRECATED_IN_FUTURE,
459465
AMBIGUOUS_ASSOCIATED_ITEMS,
466+
NESTED_IMPL_TRAIT,
460467
)
461468
}
462469
}
@@ -474,6 +481,7 @@ pub enum BuiltinLintDiagnostics {
474481
ElidedLifetimesInPaths(usize, Span, bool, Span, String),
475482
UnknownCrateTypes(Span, String, String),
476483
UnusedImports(String, Vec<(Span, String)>),
484+
NestedImplTrait { outer_impl_trait_span: Span, inner_impl_trait_span: Span },
477485
}
478486

479487
impl BuiltinLintDiagnostics {
@@ -564,6 +572,12 @@ impl BuiltinLintDiagnostics {
564572
);
565573
}
566574
}
575+
BuiltinLintDiagnostics::NestedImplTrait {
576+
outer_impl_trait_span, inner_impl_trait_span
577+
} => {
578+
db.span_label(outer_impl_trait_span, "outer `impl Trait`");
579+
db.span_label(inner_impl_trait_span, "nested `impl Trait` here");
580+
}
567581
}
568582
}
569583
}

src/librustc_lint/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
353353
reference: "issue #57593 <https://github.com/rust-lang/rust/issues/57593>",
354354
edition: None,
355355
},
356+
FutureIncompatibleInfo {
357+
id: LintId::of(NESTED_IMPL_TRAIT),
358+
reference: "issue #59014 <https://github.com/rust-lang/rust/issues/59014>",
359+
edition: None,
360+
},
356361
]);
357362

358363
// Register renamed and removed lints.

src/librustc_passes/ast_validation.rs

+65-15
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use std::mem;
1010
use syntax::print::pprust;
1111
use rustc::lint;
12+
use rustc::lint::builtin::{BuiltinLintDiagnostics, NESTED_IMPL_TRAIT};
1213
use rustc::session::Session;
1314
use rustc_data_structures::fx::FxHashMap;
1415
use syntax::ast::*;
@@ -36,9 +37,32 @@ struct AstValidator<'a> {
3637
// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
3738
// or `Foo::Bar<impl Trait>`
3839
is_impl_trait_banned: bool,
40+
41+
// rust-lang/rust#57979: the ban of nested `impl Trait` was buggy
42+
// until sometime after PR #57730 landed: it would jump directly
43+
// to walk_ty rather than visit_ty (or skip recurring entirely for
44+
// impl trait in projections), and thus miss some cases. We track
45+
// whether we should downgrade to a warning for short-term via
46+
// these booleans.
47+
warning_period_57979_nested_impl_trait: bool,
48+
warning_period_57979_impl_trait_in_proj: bool,
3949
}
4050

4151
impl<'a> AstValidator<'a> {
52+
fn with_nested_impl_trait_warning<T>(&mut self, v: bool, f: impl FnOnce(&mut Self) -> T) -> T {
53+
let old = mem::replace(&mut self.warning_period_57979_nested_impl_trait, v);
54+
let ret = f(self);
55+
self.warning_period_57979_nested_impl_trait = old;
56+
ret
57+
}
58+
59+
fn with_impl_trait_in_proj_warning<T>(&mut self, v: bool, f: impl FnOnce(&mut Self) -> T) -> T {
60+
let old = mem::replace(&mut self.warning_period_57979_impl_trait_in_proj, v);
61+
let ret = f(self);
62+
self.warning_period_57979_impl_trait_in_proj = old;
63+
ret
64+
}
65+
4266
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
4367
let old = mem::replace(&mut self.is_impl_trait_banned, true);
4468
f(self);
@@ -406,22 +430,41 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
406430
}
407431
TyKind::ImplTrait(_, ref bounds) => {
408432
if self.is_impl_trait_banned {
409-
struct_span_err!(self.session, ty.span, E0667,
410-
"`impl Trait` is not allowed in path parameters").emit();
433+
if self.warning_period_57979_impl_trait_in_proj {
434+
self.session.buffer_lint(
435+
NESTED_IMPL_TRAIT, ty.id, ty.span,
436+
"`impl Trait` is not allowed in path parameters");
437+
} else {
438+
struct_span_err!(self.session, ty.span, E0667,
439+
"`impl Trait` is not allowed in path parameters").emit();
440+
}
411441
}
412442

413443
if let Some(outer_impl_trait) = self.outer_impl_trait {
414-
struct_span_err!(self.session, ty.span, E0666,
415-
"nested `impl Trait` is not allowed")
416-
.span_label(outer_impl_trait, "outer `impl Trait`")
417-
.span_label(ty.span, "nested `impl Trait` here")
418-
.emit();
419-
444+
if self.warning_period_57979_nested_impl_trait {
445+
self.session.buffer_lint_with_diagnostic(
446+
NESTED_IMPL_TRAIT, ty.id, ty.span,
447+
"nested `impl Trait` is not allowed",
448+
BuiltinLintDiagnostics::NestedImplTrait {
449+
outer_impl_trait_span: outer_impl_trait,
450+
inner_impl_trait_span: ty.span,
451+
});
452+
} else {
453+
struct_span_err!(self.session, ty.span, E0666,
454+
"nested `impl Trait` is not allowed")
455+
.span_label(outer_impl_trait, "outer `impl Trait`")
456+
.span_label(ty.span, "nested `impl Trait` here")
457+
.emit();
458+
}
420459
}
460+
421461
if !bounds.iter()
422462
.any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) {
423463
self.err_handler().span_err(ty.span, "at least one trait must be specified");
424464
}
465+
466+
self.with_impl_trait_in_proj_warning(true, |this| this.walk_ty(ty));
467+
return;
425468
}
426469
_ => {}
427470
}
@@ -606,18 +649,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
606649
GenericArg::Const(..) => ParamKindOrd::Const,
607650
}, arg.span(), None)
608651
}), GenericPosition::Arg, generic_args.span());
609-
// Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
610-
// are allowed to contain nested `impl Trait`.
611-
self.with_impl_trait(None, |this| {
612-
walk_list!(this, visit_assoc_type_binding, &data.bindings);
652+
653+
self.with_nested_impl_trait_warning(true, |this| {
654+
// Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
655+
// are allowed to contain nested `impl Trait`.
656+
this.with_impl_trait(None, |this| {
657+
walk_list!(this, visit_assoc_type_binding, &data.bindings);
658+
});
613659
});
614660
}
615661
GenericArgs::Parenthesized(ref data) => {
616662
walk_list!(self, visit_ty, &data.inputs);
617663
if let Some(ref type_) = data.output {
618-
// `-> Foo` syntax is essentially an associated type binding,
619-
// so it is also allowed to contain nested `impl Trait`.
620-
self.with_impl_trait(None, |this| this.visit_ty(type_));
664+
self.with_nested_impl_trait_warning(true, |this| {
665+
// `-> Foo` syntax is essentially an associated type binding,
666+
// so it is also allowed to contain nested `impl Trait`.
667+
this.with_impl_trait(None, |this| this.visit_ty(type_));
668+
});
621669
}
622670
}
623671
}
@@ -719,6 +767,8 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) {
719767
has_global_allocator: false,
720768
outer_impl_trait: None,
721769
is_impl_trait_banned: false,
770+
warning_period_57979_nested_impl_trait: false,
771+
warning_period_57979_impl_trait_in_proj: false,
722772
};
723773
visit::walk_crate(&mut validator, krate);
724774

0 commit comments

Comments
 (0)