diff options
| author | leonardo.yvens <leoyvens@gmail.com> | 2018-05-12 16:43:42 -0300 |
|---|---|---|
| committer | Mark Simulacrum <mark.simulacrum@gmail.com> | 2018-05-24 14:50:32 -0600 |
| commit | 5b73750ed182c95755316a667fe68a653976dfb2 (patch) | |
| tree | 3f673356f9c45aad409f829f576240ddda26e143 | |
| parent | 07c42af554c989c536ed2814b476f52239c2434f (diff) | |
| download | rust-5b73750ed182c95755316a667fe68a653976dfb2.tar.gz rust-5b73750ed182c95755316a667fe68a653976dfb2.zip | |
Fix self referential impl Trait substitutions
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
| -rw-r--r-- | src/librustc_privacy/lib.rs | 15 | ||||
| -rw-r--r-- | src/test/run-pass/impl-trait/issue-49376.rs | 29 |
2 files changed, 42 insertions, 2 deletions
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 95be691b30c..4e899d84574 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -31,6 +31,7 @@ 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; @@ -39,6 +40,7 @@ use syntax_pos::hygiene::SyntaxContext; use std::cmp; use std::mem::replace; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; mod diagnostics; @@ -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> { @@ -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; } @@ -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); diff --git a/src/test/run-pass/impl-trait/issue-49376.rs b/src/test/run-pass/impl-trait/issue-49376.rs new file mode 100644 index 00000000000..b687b485fce --- /dev/null +++ b/src/test/run-pass/impl-trait/issue-49376.rs @@ -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() {} |
