Skip to content
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

in region, treat current (and future) item-likes alike #37920

Merged
merged 4 commits into from
Dec 4, 2016

Conversation

nikomatsakis
Copy link
Contributor

The visit_fn code mutates its surrounding context. Between items,
this was saved/restored, but between impl items it was not. This meant
that we wound up with CallSiteScope entries with two parents (or
more!). As far as I can tell, this is harmless in actual type-checking,
since the regions you interact with are always from at most one of those
branches. But it can slow things down.

Before, the effect was limited, since it only applied to impl items
within an impl. After #37660, impl items are visisted all together at
the end, and hence this could create a very messed up
hierarchy. Isolating impl item properly solves both issues.

I cannot come up with a way to unit-test this; for posterity, however,
you can observe the messed up hierarchies with a test as simple as the
following, which would create a callsite scope with two parents both
before and after

struct Foo {
}

impl Foo {
    fn bar(&self) -> usize {
        22
    }

    fn baz(&self) -> usize {
        22
    }
}

fn main() { }

Fixes #37864.

r? @michaelwoerister

cc @pnkfelix -- can you think of a way to make a regr test?

@arielb1
Copy link
Contributor

arielb1 commented Nov 21, 2016

For example, the following lint could do:

#![feature(plugin_registrar, rustc_private)]

extern crate syntax;
#[macro_use]
extern crate rustc;
extern crate rustc_plugin;

use rustc::lint::{LateContext, LintPass, LateLintPass, LintArray, LintContext};
use rustc::hir;
use rustc::hir::intravisit::FnKind;
use rustc::middle::region::CodeExtent;
use rustc::util::nodemap::FnvHashMap;

use syntax::ast::{self, NodeId};
use syntax::codemap::Span;

declare_lint!(REGION_HIERARCHY, Warn, "warn about bogus region hierarchy");

struct Pass {
    map: FnvHashMap<CodeExtent, NodeId>
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray { lint_array!(REGION_HIERARCHY) }
}

impl LateLintPass for Pass {
    fn check_fn(&mut self, cx: &LateContext,
                fk: FnKind, _: &hir::FnDecl, expr: &hir::Block,
                span: Span, node: ast::NodeId)
    {
        if let FnKind::Closure(..) = fk { return }

        let mut extent = cx.tcx.region_maps.node_extent(expr.id);
        while let Some(parent) = cx.tcx.region_maps.opt_encl_scope(extent) {
            extent = parent;
        }
        if let Some(other) = self.map.insert(extent, node) {
            cx.span_lint(REGION_HIERARCHY, span, &format!(
                "different fns {:?}, {:?} with the same root extent {:?}",
                cx.tcx.map.local_def_id(other),
                cx.tcx.map.local_def_id(node),
                extent));
        }
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut ::rustc_plugin::Registry) {
    reg.register_late_lint_pass(Box::new(
        Pass { map: FnvHashMap() }
    ));
}

@michaelwoerister
Copy link
Member

The fix looks good to me. Do you still want to experiment with adding a test case for this?

@nikomatsakis
Copy link
Contributor Author

The fix looks good to me. Do you still want to experiment with adding a test case for this?

I'm torn. The idea of a custom lint is clever. But it seems like a lot of effort for a data structure I would hope that we will overhaul in the not that distant future...

@nikomatsakis
Copy link
Contributor Author

Well, @arielb1's lint basically works right off, so I might as well add it =)

@nnethercote
Copy link
Contributor

The CI is failing due to some C++ compile error involving LLVM that I don't understand.

@bors
Copy link
Contributor

bors commented Nov 29, 2016

☔ The latest upstream changes (presumably #37918) made this pull request unmergeable. Please resolve the merge conflicts.

// aux-build:lint.rs

#![feature(plugin)]
#![plugin(lint)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you need #![deny(region_hierarchy)] so that the test will actually fail?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose I do...

The `visit_fn` code mutates its surrounding context.  Between *items*,
this was saved/restored, but between impl items it was not. This meant
that we wound up with `CallSiteScope` entries with two parents (or
more!).  As far as I can tell, this is harmless in actual type-checking,
since the regions you interact with are always from at most one of those
branches. But it can slow things down.

Before, the effect was limited, since it only applied to impl items
within an impl. After rust-lang#37660, impl items are visisted all together at
the end, and hence this could create a very messed up
hierarchy. Isolating impl item properly solves both issues.

I cannot come up with a way to unit-test this; for posterity, however,
you can observe the messed up hierarchies with a test as simple as the
following, which would create a callsite scope with two parents both
before and after

```
struct Foo {
}

impl Foo {
    fn bar(&self) -> usize {
        22
    }

    fn baz(&self) -> usize {
        22
    }
}

fn main() { }
```

Fixes rust-lang#37864.
@nikomatsakis
Copy link
Contributor Author

@bors r=mw

@bors
Copy link
Contributor

bors commented Dec 1, 2016

📌 Commit 6fe4bff has been approved by mw

@bors
Copy link
Contributor

bors commented Dec 2, 2016

⌛ Testing commit 6fe4bff with merge 76c66a9...

bors added a commit that referenced this pull request Dec 2, 2016
in region, treat current (and future) item-likes alike

The `visit_fn` code mutates its surrounding context.  Between *items*,
this was saved/restored, but between impl items it was not. This meant
that we wound up with `CallSiteScope` entries with two parents (or
more!).  As far as I can tell, this is harmless in actual type-checking,
since the regions you interact with are always from at most one of those
branches. But it can slow things down.

Before, the effect was limited, since it only applied to impl items
within an impl. After #37660, impl items are visisted all together at
the end, and hence this could create a very messed up
hierarchy. Isolating impl item properly solves both issues.

I cannot come up with a way to unit-test this; for posterity, however,
you can observe the messed up hierarchies with a test as simple as the
following, which would create a callsite scope with two parents both
before and after

```
struct Foo {
}

impl Foo {
    fn bar(&self) -> usize {
        22
    }

    fn baz(&self) -> usize {
        22
    }
}

fn main() { }
```

Fixes #37864.

r? @michaelwoerister

cc @pnkfelix -- can you think of a way to make a regr test?
@bors
Copy link
Contributor

bors commented Dec 2, 2016

💔 Test failed - auto-win-gnu-32-opt-rustbuild

@michaelwoerister
Copy link
Member

tidy error:

C:\bot\slave\auto-win-gnu-32-opt-rustbuild\build\src\librustc\middle\region.rs:1069: line longer than 100 chars

@nikomatsakis
Copy link
Contributor Author

Bah humbug.

@nikomatsakis
Copy link
Contributor Author

@bors r=mw

@bors
Copy link
Contributor

bors commented Dec 2, 2016

📌 Commit 0adb1b1 has been approved by mw

@bors
Copy link
Contributor

bors commented Dec 2, 2016

⌛ Testing commit 0adb1b1 with merge 4ba1de1...

@bors
Copy link
Contributor

bors commented Dec 2, 2016

💔 Test failed - auto-mac-64-opt

@alexcrichton
Copy link
Member

alexcrichton commented Dec 2, 2016 via email

@bors
Copy link
Contributor

bors commented Dec 2, 2016

⌛ Testing commit 0adb1b1 with merge ae10b64...

bors added a commit that referenced this pull request Dec 2, 2016
in region, treat current (and future) item-likes alike

The `visit_fn` code mutates its surrounding context.  Between *items*,
this was saved/restored, but between impl items it was not. This meant
that we wound up with `CallSiteScope` entries with two parents (or
more!).  As far as I can tell, this is harmless in actual type-checking,
since the regions you interact with are always from at most one of those
branches. But it can slow things down.

Before, the effect was limited, since it only applied to impl items
within an impl. After #37660, impl items are visisted all together at
the end, and hence this could create a very messed up
hierarchy. Isolating impl item properly solves both issues.

I cannot come up with a way to unit-test this; for posterity, however,
you can observe the messed up hierarchies with a test as simple as the
following, which would create a callsite scope with two parents both
before and after

```
struct Foo {
}

impl Foo {
    fn bar(&self) -> usize {
        22
    }

    fn baz(&self) -> usize {
        22
    }
}

fn main() { }
```

Fixes #37864.

r? @michaelwoerister

cc @pnkfelix -- can you think of a way to make a regr test?
@bors
Copy link
Contributor

bors commented Dec 3, 2016

💔 Test failed - auto-linux-musl-64-opt

@arielb1
Copy link
Contributor

arielb1 commented Dec 3, 2016

---- [run-pass] run-pass/issue-37290/main.rs stdout ----
	
error: auxiliary build of "/buildslave/rust-buildbot/slave/auto-linux-musl-64-opt/build/src/test/run-pass/issue-37290/auxiliary/lint.rs" failed to compile: 
status: exit code: 101
command: x86_64-unknown-linux-gnu/stage2/bin/rustc /buildslave/rust-buildbot/slave/auto-linux-musl-64-opt/build/src/test/run-pass/issue-37290/auxiliary/lint.rs -L x86_64-unknown-linux-gnu/test/run-pass/ --target=x86_64-unknown-linux-musl --error-format json --crate-type=lib -L x86_64-unknown-linux-gnu/test/run-pass/issue-37290/main.stage2-x86_64-unknown-linux-musl.run-pass.libaux -C prefer-dynamic --out-dir x86_64-unknown-linux-gnu/test/run-pass/issue-37290/main.stage2-x86_64-unknown-linux-musl.run-pass.libaux -C linker=/musl-x86_64/bin/musl-gcc -C ar=ar --cfg rtopt -C rpath -O -L x86_64-unknown-linux-musl/rt -C prefer-dynamic
stdout:
------------------------------------------

------------------------------------------
stderr:
------------------------------------------
{"message":"can't find crate for `syntax`","code":{"code":"E0463","explanation":"\nA plugin/crate was declared but cannot be found. Erroneous code example:\n\n```compile_fail,E0463\n#![feature(plugin)]\n#![plugin(cookie_monster)] // error: can't find crate for `cookie_monster`\nextern crate cake_is_a_lie; // error: can't find crate for `cake_is_a_lie`\n```\n\nYou need to link your code to the relevant crate in order to be able to use it\n(through Cargo or the `-L` option of rustc example). Plugins are crates as\nwell, and you link to them the same way.\n"},"level":"error","spans":[{"file_name":"/buildslave/rust-buildbot/slave/auto-linux-musl-64-opt/build/src/test/run-pass/issue-37290/auxiliary/lint.rs","byte_start":651,"byte_end":671,"line_start":18,"line_end":18,"column_start":1,"column_end":21,"is_primary":true,"text":[{"text":"extern crate syntax;","highlight_start":1,"highlight_end":21}],"label":"can't find crate","suggested_replacement":null,"expansion":null}],"children":[],"rendered":null}
{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":null}

The test needs to be in run-pass-fulldeps I think.

@nikomatsakis
Copy link
Contributor Author

@bors r=mw

@bors
Copy link
Contributor

bors commented Dec 3, 2016

📌 Commit f809706 has been approved by mw

@bors
Copy link
Contributor

bors commented Dec 4, 2016

⌛ Testing commit f809706 with merge d14d74d...

bors added a commit that referenced this pull request Dec 4, 2016
in region, treat current (and future) item-likes alike

The `visit_fn` code mutates its surrounding context.  Between *items*,
this was saved/restored, but between impl items it was not. This meant
that we wound up with `CallSiteScope` entries with two parents (or
more!).  As far as I can tell, this is harmless in actual type-checking,
since the regions you interact with are always from at most one of those
branches. But it can slow things down.

Before, the effect was limited, since it only applied to impl items
within an impl. After #37660, impl items are visisted all together at
the end, and hence this could create a very messed up
hierarchy. Isolating impl item properly solves both issues.

I cannot come up with a way to unit-test this; for posterity, however,
you can observe the messed up hierarchies with a test as simple as the
following, which would create a callsite scope with two parents both
before and after

```
struct Foo {
}

impl Foo {
    fn bar(&self) -> usize {
        22
    }

    fn baz(&self) -> usize {
        22
    }
}

fn main() { }
```

Fixes #37864.

r? @michaelwoerister

cc @pnkfelix -- can you think of a way to make a regr test?
@bors bors merged commit f809706 into rust-lang:master Dec 4, 2016
@nikomatsakis nikomatsakis deleted the compile-time-regression-37864 branch April 14, 2017 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants