Skip to content

Rolling up PRs in the queue #24674

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 59 commits into from
Apr 22, 2015
Merged
Changes from 1 commit
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
8f5b5f9
std: Add Default/IntoIterator/ToOwned to the prelude
alexcrichton Apr 17, 2015
dc59669
Fix typos
mdinger Apr 21, 2015
9cc0af8
Refocus unsafe code chapter on unsafe itself.
steveklabnik Apr 20, 2015
265a7cc
Add a `write_char` method to `std::fmt::Write`
SimonSapin Apr 21, 2015
ba276ad
LLVM < 3.5 is unsupported since bb18a3c
tamird Apr 20, 2015
7a0df61
add TCP_* consts for linux
dovahcrow Apr 21, 2015
32e5f49
Remove unused files
tamird Apr 21, 2015
fe7f95f
Remove dead test
tamird Apr 21, 2015
71bc70e
Remove references to `old_{path,io}`
tamird Apr 21, 2015
19cc943
write_char is unlikely to make it for 1.0, it’ll be 1.1
SimonSapin Apr 21, 2015
dd24070
Check for shadowing between lifetimes and loop labels in function bod…
pnkfelix Apr 3, 2015
ccc9f5e
Tests for shadowing between lifetimes and loop labels within function…
pnkfelix Apr 8, 2015
2b3cd40
add notes clarifying introduction of warnings for a pair of run-pass …
pnkfelix Apr 21, 2015
3cc84ef
Deprecate std::fs::soft_link in favor of platform-specific versions
lambda Apr 9, 2015
16181e6
Pick a feature name for write_char
SimonSapin Apr 21, 2015
5f7556c
Add an example of completely slicing an object.
sw17ch Apr 21, 2015
a4541b0
syntax: remove #![feature(box_syntax, box_patterns)]
erickt Apr 16, 2015
ca0ee4c
syntax: Remove uses of #[feature(slice_patterns)]
erickt Apr 16, 2015
cfb9d28
syntax: remove uses of `.into_cow()`
erickt Apr 16, 2015
e3dd68d
syntax: Remove use of TraitObject in pretty printer
erickt Apr 17, 2015
bc6d990
syntax: Don't use unstable fn to convert single element to a slice
erickt Apr 17, 2015
8553658
syntax: remove #[feature(quote, unsafe_destructor)]
erickt Apr 17, 2015
2937cce
syntax: Replace String::from_str with the stable String::from
erickt Apr 17, 2015
a2cfe38
syntax: Replace [].tail with the stable [1..] syntax
erickt Apr 17, 2015
21143aa
syntax: Replace Vec::map_in_place with stable mut iterator
erickt Apr 17, 2015
c3da1a1
syntax: replace Vec::push_all with stable Vec::extend
erickt Apr 17, 2015
83b1d7f
syntax: Remove #[feature(path_ext)]
erickt Apr 19, 2015
7f9180f
syntax: Change ExpnId::{from,to}_llvm_cookie to {from,to}_u32
erickt Apr 21, 2015
0070625
small edits for recently written book chapters
steveklabnik Apr 21, 2015
19c8d70
syntax: Copy unstable str::char_at into libsyntax
erickt Apr 21, 2015
f0a3b6c
Add research to README of TRPL
steveklabnik Apr 21, 2015
5c70ff0
Bump version to 1.1.0
brson Apr 21, 2015
9ab0475
rustc: Handle duplicate names merging archives
alexcrichton Apr 14, 2015
b0105b5
TRPL editing: tuple structs
steveklabnik Apr 21, 2015
f43c86c
unstabilize Words struct
kwantam Apr 21, 2015
c361e13
implement rfc 1054: split_whitespace() fn, deprecate words()
kwantam Apr 18, 2015
f78ee1a
Document functional update syntax
steveklabnik Apr 21, 2015
2baf348
Auto merge of #24162 - pnkfelix:fsk-detect-duplicate-loop-labels, r=n…
bors Apr 21, 2015
75f3565
rollup merge of #24162: pnkfelix/fsk-detect-duplicate-loop-labels
alexcrichton Apr 21, 2015
2fc2e12
rollup merge of #24222: lambda/rename-soft-link-to-symlink
alexcrichton Apr 21, 2015
957cb42
rollup merge of #24439: alexcrichton/fix-archive-assembler
alexcrichton Apr 21, 2015
37a1f2e
rollup merge of #24487: erickt/syntax
alexcrichton Apr 21, 2015
a63df92
rollup merge of #24563: kwantam/rfc_1054
alexcrichton Apr 21, 2015
6b1ce49
rollup merge of #24611: doomsplayer/doomsplayer-patch-1
alexcrichton Apr 21, 2015
d14fb2f
rollup merge of #24635: tamird/llvm-3.5
alexcrichton Apr 21, 2015
1ec7ccb
rollup merge of #24640: steveklabnik/new_unsafe_guide
alexcrichton Apr 21, 2015
59171f8
rollup merge of #24651: tamird/old-references
alexcrichton Apr 21, 2015
251f8d3
rollup merge of #24654: mdinger/patch-2
alexcrichton Apr 21, 2015
c7017b3
rollup merge of #24661: SimonSapin/fmt-write-char
alexcrichton Apr 21, 2015
ee9d4ee
rollup merge of #24663: steveklabnik/gh24639
alexcrichton Apr 21, 2015
1a6c18d
rollup merge of #24665: sw17ch/document-complete-slice-syntax
alexcrichton Apr 21, 2015
83008b2
rollup merge of #24667: steveklabnik/more_editing
alexcrichton Apr 21, 2015
0feaf61
rollup merge of #24669: steveklabnik/fix
alexcrichton Apr 21, 2015
cfbc5be
rollup merge of #24670: brson/1.1
alexcrichton Apr 21, 2015
44338cb
rollup merge of #24672: steveklabnik/edit_tuple_structs
alexcrichton Apr 21, 2015
98e9765
rollup merge of #24541: alexcrichton/issue-24538
alexcrichton Apr 21, 2015
a1dd5ac
rollup merge of #24636: alexcrichton/remove-deprecated
alexcrichton Apr 21, 2015
224fc10
Test fixes and rebase conflicts, round 1
alexcrichton Apr 21, 2015
5815064
Merge remote-tracking branch 'origin/master' into rollup
alexcrichton Apr 21, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Check for shadowing between lifetimes and loop labels in function bod…
…ies.

Note: this Warns rather than error on shadowing problems involving labels.
We took this more conservative option mostly due to issues with
hygiene being broken for labels and/or lifetimes.

Add FIXME regarding non-hygienic comparison.
  • Loading branch information
pnkfelix committed Apr 21, 2015
commit dd240707999216a64e7914c2290cb59c54d9c60c
213 changes: 201 additions & 12 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use middle::region;
use middle::subst;
use middle::ty;
use std::fmt;
use std::mem::replace;
use syntax::ast;
use syntax::codemap::Span;
use syntax::parse::token::special_idents;
Expand Down Expand Up @@ -70,6 +71,9 @@ struct LifetimeContext<'a> {

// I'm sorry.
trait_ref_hack: bool,

// List of labels in the function/method currently under analysis.
labels_in_fn: Vec<(ast::Ident, Span)>,
}

enum ScopeChain<'a> {
Expand Down Expand Up @@ -97,13 +101,18 @@ pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegio
scope: &ROOT_SCOPE,
def_map: def_map,
trait_ref_hack: false,
labels_in_fn: vec![],
}, krate);
sess.abort_if_errors();
named_region_map
}

impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
fn visit_item(&mut self, item: &ast::Item) {
// Items save/restore the set of labels. This way innner items
// can freely reuse names, be they loop labels or lifetimes.
let saved = replace(&mut self.labels_in_fn, vec![]);

// Items always introduce a new root scope
self.with(RootScope, |_, this| {
match item.node {
Expand Down Expand Up @@ -137,23 +146,26 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
}
}
});

// Done traversing the item; restore saved set of labels.
replace(&mut self.labels_in_fn, saved);
}

fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
b: &'v ast::Block, s: Span, _: ast::NodeId) {
match fk {
visit::FkItemFn(_, generics, _, _, _) => {
self.visit_early_late(subst::FnSpace, generics, |this| {
visit::walk_fn(this, fk, fd, b, s)
this.walk_fn(fk, fd, b, s)
})
}
visit::FkMethod(_, sig, _) => {
self.visit_early_late(subst::FnSpace, &sig.generics, |this| {
visit::walk_fn(this, fk, fd, b, s)
this.walk_fn(fk, fd, b, s)
})
}
visit::FkFnBlock(..) => {
visit::walk_fn(self, fk, fd, b, s)
self.walk_fn(fk, fd, b, s)
}
}
}
Expand Down Expand Up @@ -190,13 +202,19 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
}

fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
// We reset the labels on every trait item, so that different
// methods in an impl can reuse label names.
let saved = replace(&mut self.labels_in_fn, vec![]);

if let ast::MethodTraitItem(ref sig, None) = trait_item.node {
self.visit_early_late(
subst::FnSpace, &sig.generics,
|this| visit::walk_trait_item(this, trait_item))
} else {
visit::walk_trait_item(self, trait_item);
}

replace(&mut self.labels_in_fn, saved);
}

fn visit_block(&mut self, b: &ast::Block) {
Expand Down Expand Up @@ -286,7 +304,170 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
}
}

#[derive(Copy, Clone, PartialEq)]
enum ShadowKind { Label, Lifetime }
struct Original { kind: ShadowKind, span: Span }
struct Shadower { kind: ShadowKind, span: Span }

fn original_label(span: Span) -> Original {
Original { kind: ShadowKind::Label, span: span }
}
fn shadower_label(span: Span) -> Shadower {
Shadower { kind: ShadowKind::Label, span: span }
}
fn original_lifetime(l: &ast::Lifetime) -> Original {
Original { kind: ShadowKind::Lifetime, span: l.span }
}
fn shadower_lifetime(l: &ast::Lifetime) -> Shadower {
Shadower { kind: ShadowKind::Lifetime, span: l.span }
}

impl ShadowKind {
fn desc(&self) -> &'static str {
match *self {
ShadowKind::Label => "label",
ShadowKind::Lifetime => "lifetime",
}
}
}

fn signal_shadowing_problem(
sess: &Session, name: ast::Name, orig: Original, shadower: Shadower) {
if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
// lifetime/lifetime shadowing is an error
sess.span_err(shadower.span,
&format!("{} name `{}` shadows a \
{} name that is already in scope",
shadower.kind.desc(), name, orig.kind.desc()));
} else {
// shadowing involving a label is only a warning, due to issues with
// labels and lifetimes not being macro-hygienic.
sess.span_warn(shadower.span,
&format!("{} name `{}` shadows a \
{} name that is already in scope",
shadower.kind.desc(), name, orig.kind.desc()));
}
sess.span_note(orig.span,
&format!("shadowed {} `{}` declared here",
orig.kind.desc(), name));
}

// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
// if one of the label shadows a lifetime or another label.
fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v ast::Block) {

struct GatherLabels<'a> {
sess: &'a Session,
scope: Scope<'a>,
labels_in_fn: &'a mut Vec<(ast::Ident, Span)>,
}

let mut gather = GatherLabels {
sess: ctxt.sess,
scope: ctxt.scope,
labels_in_fn: &mut ctxt.labels_in_fn,
};
gather.visit_block(b);
return;

impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
fn visit_expr(&mut self, ex: &'v ast::Expr) {
if let Some(label) = expression_label(ex) {
for &(prior, prior_span) in &self.labels_in_fn[..] {
// FIXME (#24278): non-hygienic comparision
if label.name == prior.name {
signal_shadowing_problem(self.sess,
label.name,
original_label(prior_span),
shadower_label(ex.span));
}
}

check_if_label_shadows_lifetime(self.sess,
self.scope,
label,
ex.span);

self.labels_in_fn.push((label, ex.span));
}
visit::walk_expr(self, ex)
}

fn visit_item(&mut self, _: &ast::Item) {
// do not recurse into items defined in the block
}
}

fn expression_label(ex: &ast::Expr) -> Option<ast::Ident> {
match ex.node {
ast::ExprWhile(_, _, Some(label)) |
ast::ExprWhileLet(_, _, _, Some(label)) |
ast::ExprForLoop(_, _, _, Some(label)) |
ast::ExprLoop(_, Some(label)) => Some(label),
_ => None,
}
}

fn check_if_label_shadows_lifetime<'a>(sess: &'a Session,
mut scope: Scope<'a>,
label: ast::Ident,
label_span: Span) {
loop {
match *scope {
BlockScope(_, s) => { scope = s; }
RootScope => { return; }

EarlyScope(_, lifetimes, s) |
LateScope(lifetimes, s) => {
for lifetime_def in lifetimes {
// FIXME (#24278): non-hygienic comparision
if label.name == lifetime_def.lifetime.name {
signal_shadowing_problem(
sess,
label.name,
original_lifetime(&lifetime_def.lifetime),
shadower_label(label_span));
return;
}
}
scope = s;
}
}
}
}
}

impl<'a> LifetimeContext<'a> {
// This is just like visit::walk_fn, except that it extracts the
// labels of the function body and swaps them in before visiting
// the function body itself.
fn walk_fn<'b>(&mut self,
fk: visit::FnKind,
fd: &ast::FnDecl,
fb: &'b ast::Block,
_span: Span) {
match fk {
visit::FkItemFn(_, generics, _, _, _) => {
visit::walk_fn_decl(self, fd);
self.visit_generics(generics);
}
visit::FkMethod(_, sig, _) => {
visit::walk_fn_decl(self, fd);
self.visit_generics(&sig.generics);
self.visit_explicit_self(&sig.explicit_self);
}
visit::FkFnBlock(..) => {
visit::walk_fn_decl(self, fd);
}
}

// After inpsecting the decl, add all labels from the body to
// `self.labels_in_fn`.
extract_labels(self, fb);

self.visit_block(fb);
}

fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
F: FnOnce(Scope, &mut LifetimeContext),
{
Expand All @@ -297,6 +478,7 @@ impl<'a> LifetimeContext<'a> {
scope: &wrap_scope,
def_map: self.def_map,
trait_ref_hack: self.trait_ref_hack,
labels_in_fn: self.labels_in_fn.clone(),
};
debug!("entering scope {:?}", this.scope);
f(self.scope, &mut this);
Expand Down Expand Up @@ -494,6 +676,17 @@ impl<'a> LifetimeContext<'a> {
mut old_scope: Scope,
lifetime: &ast::Lifetime)
{
for &(label, label_span) in &self.labels_in_fn {
// FIXME (#24278): non-hygienic comparision
if lifetime.name == label.name {
signal_shadowing_problem(self.sess,
lifetime.name,
original_label(label_span),
shadower_lifetime(&lifetime));
return;
}
}

loop {
match *old_scope {
BlockScope(_, s) => {
Expand All @@ -507,15 +700,11 @@ impl<'a> LifetimeContext<'a> {
EarlyScope(_, lifetimes, s) |
LateScope(lifetimes, s) => {
if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) {
self.sess.span_err(
lifetime.span,
&format!("lifetime name `{}` shadows another \
lifetime name that is already in scope",
token::get_name(lifetime.name)));
self.sess.span_note(
lifetime_def.span,
&format!("shadowed lifetime `{}` declared here",
token::get_name(lifetime.name)));
signal_shadowing_problem(
self.sess,
lifetime.name,
original_lifetime(&lifetime_def),
shadower_lifetime(&lifetime));
return;
}

Expand Down