Skip to content

Commit

Permalink
Fix self referential impl Trait substitutions
Browse files Browse the repository at this point in the history
A high impact bug because a lot of common traits use a `Self`
substitution by default. Should be backported to beta.

There was a check for this which wasn't catching all cases, it was made
more robust.

Fixes #49376
Fixes #50626

r? @petrochenkov
  • Loading branch information
leoyvens committed May 12, 2018
1 parent e6db79f commit 56bc4c2
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 2 deletions.
15 changes: 13 additions & 2 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ use rustc::middle::privacy::{AccessLevel, AccessLevels};
use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
use rustc::ty::fold::TypeVisitor;
use rustc::ty::maps::Providers;
use rustc::ty::subst::UnpackedKind;
use rustc::util::nodemap::NodeSet;
use syntax::ast::{self, CRATE_NODE_ID, Ident};
use syntax::symbol::keywords;
use syntax_pos::Span;

use std::cmp;
use std::mem::replace;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;

mod diagnostics;
Expand Down Expand Up @@ -624,6 +626,7 @@ struct TypePrivacyVisitor<'a, 'tcx: 'a> {
in_body: bool,
span: Span,
empty_tables: &'a ty::TypeckTables<'tcx>,
visited_anon_tys: FxHashSet<DefId>
}

impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
Expand Down Expand Up @@ -943,8 +946,15 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
self.tcx.sess.span_err(self.span, &msg);
return true;
}
// `Self` here is the same `TyAnon`, so skip it to avoid infinite recursion
for subst in trait_ref.substs.iter().skip(1) {
for subst in trait_ref.substs.iter() {
// Skip repeated `TyAnon`s to avoid infinite recursion.
if let UnpackedKind::Type(ty) = subst.unpack() {
if let ty::TyAnon(def_id, ..) = ty.sty {
if !self.visited_anon_tys.insert(def_id) {
continue;
}
}
}
if subst.visit_with(self) {
return true;
}
Expand Down Expand Up @@ -1677,6 +1687,7 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
in_body: false,
span: krate.span,
empty_tables: &empty_tables,
visited_anon_tys: FxHashSet()
};
intravisit::walk_crate(&mut visitor, krate);

Expand Down
29 changes: 29 additions & 0 deletions src/test/run-pass/impl-trait/issue-49376.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Tests for nested self-reference which caused a stack overflow.

use std::fmt::Debug;
use std::ops::*;

fn gen() -> impl PartialOrd + PartialEq + Debug { }

struct Bar {}
trait Foo<T = Self> {}
impl Foo for Bar {}

fn foo() -> impl Foo {
Bar {}
}

fn test_impl_ops() -> impl Add + Sub + Mul + Div { 1 }
fn test_impl_assign_ops() -> impl AddAssign + SubAssign + MulAssign + DivAssign { 1 }

fn main() {}

0 comments on commit 56bc4c2

Please sign in to comment.