Skip to content

Commit a0d0584

Browse files
committed
Correctly forbid upvars in nested impls, traits and classes
Previously, resolve was allowing impls, traits or classes that were nested within a fn to refer to upvars, as well as referring to type parameters bound by the fn. Fixing this required adding a new kind of def: def_typaram_binder, which can refer to any of an impl, trait or class that has bound ty params. resolve uses this to enforce that methods can refer to their parent item's type parameters, but not to outer items' type parameters; other stages ignore it. I also made sure that impl, trait and class methods get checked inside a MethodRibKind thing so as to forbid upvars, and changed the definition of MethodRibKind so that its second argument is an optional node_id (so that required trait method signatures can be checked with a MethodRibKind as well).
1 parent e4ab0f6 commit a0d0584

File tree

11 files changed

+157
-13
lines changed

11 files changed

+157
-13
lines changed

src/libsyntax/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ enum def {
8888
@def /* closed over def */,
8989
node_id /* expr node that creates the closure */),
9090
def_class(def_id, bool /* has constructor */),
91+
def_typaram_binder(node_id), /* class, impl or trait that has ty params */
9192
def_region(node_id)
9293
}
9394

src/libsyntax/ast_util.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ pure fn def_id_of_def(d: def) -> def_id {
5555
def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
5656
def_use(id) | def_class(id, _) { id }
5757
def_arg(id, _) | def_local(id, _) | def_self(id) |
58-
def_upvar(id, _, _) | def_binding(id) | def_region(id) {
58+
def_upvar(id, _, _) | def_binding(id) | def_region(id)
59+
| def_typaram_binder(id) {
5960
local_def(id)
6061
}
6162

src/rustc/middle/astencode.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ impl of tr for ast::def {
373373
ast::def_class(did.tr(xcx), has_constructor)
374374
}
375375
ast::def_region(nid) { ast::def_region(xcx.tr_id(nid)) }
376+
ast::def_typaram_binder(nid) {
377+
ast::def_typaram_binder(xcx.tr_id(nid))
378+
}
376379
}
377380
}
378381
}

src/rustc/middle/borrowck/categorization.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,12 @@ impl public_methods for borrowck_ctxt {
192192
expr_ty: ty::t,
193193
def: ast::def) -> cmt {
194194
alt def {
195-
ast::def_fn(_, _) | ast::def_mod(_) |
195+
ast::def_fn(*) | ast::def_mod(_) |
196196
ast::def_foreign_mod(_) | ast::def_const(_) |
197-
ast::def_use(_) | ast::def_variant(_, _) |
197+
ast::def_use(_) | ast::def_variant(*) |
198198
ast::def_ty(_) | ast::def_prim_ty(_) |
199-
ast::def_ty_param(_, _) | ast::def_class(_, _) |
200-
ast::def_region(_) {
199+
ast::def_ty_param(*) | ast::def_class(*) |
200+
ast::def_typaram_binder(*) | ast::def_region(_) {
201201
@{id:id, span:span,
202202
cat:cat_special(sk_static_item), lp:none,
203203
mutbl:m_imm, ty:expr_ty}

src/rustc/middle/resolve3.rs

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import syntax::ast::{bound_send, capture_clause, class_ctor, class_dtor};
1010
import syntax::ast::{class_member, class_method, crate, crate_num, decl_item};
1111
import syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn};
1212
import syntax::ast::{def_foreign_mod, def_id, def_local, def_mod};
13-
import syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param};
13+
import syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param,
14+
def_typaram_binder};
1415
import syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op};
1516
import syntax::ast::{expr_binary, expr_cast, expr_field, expr_fn};
1617
import syntax::ast::{expr_fn_block, expr_index, expr_new, expr_path};
@@ -171,10 +172,23 @@ enum RibKind {
171172
// upvars as appropriate.
172173
FunctionRibKind(node_id),
173174

175+
// We passed through a class, impl, or trait and are now in one of its
176+
// methods. Allow references to ty params that that class, impl or trait
177+
// binds. Disallow any other upvars (including other ty params that are
178+
// upvars).
179+
// parent; method itself
180+
MethodRibKind(node_id, MethodSort),
181+
174182
// We passed through a function *item* scope. Disallow upvars.
175183
OpaqueFunctionRibKind
176184
}
177185

186+
// Methods can be required or provided. Required methods only occur in traits.
187+
enum MethodSort {
188+
Required,
189+
Provided(node_id)
190+
}
191+
178192
// The X-ray flag indicates that a context has the X-ray privilege, which
179193
// allows it to reference private names. Currently, this is used for the test
180194
// runner.
@@ -1392,7 +1406,8 @@ class Resolver {
13921406
}
13931407
def_self(*) | def_arg(*) | def_local(*) |
13941408
def_prim_ty(*) | def_ty_param(*) | def_binding(*) |
1395-
def_use(*) | def_upvar(*) | def_region(*) {
1409+
def_use(*) | def_upvar(*) | def_region(*) |
1410+
def_typaram_binder(*) {
13961411
fail #fmt("didn't expect `%?`", def);
13971412
}
13981413
}
@@ -2891,6 +2906,36 @@ class Resolver {
28912906
function_id);
28922907
}
28932908
}
2909+
MethodRibKind(item_id, method_id) {
2910+
// If the def is a ty param, and came from the parent
2911+
// item, it's ok
2912+
alt def {
2913+
def_ty_param(did, _) if self.def_map.find(copy(did.node))
2914+
== some(def_typaram_binder(item_id)) {
2915+
// ok
2916+
}
2917+
_ {
2918+
if !is_ty_param {
2919+
// This was an attempt to access an upvar inside a
2920+
// named function item. This is not allowed, so we
2921+
// report an error.
2922+
2923+
self.session.span_err(
2924+
span,
2925+
~"attempted dynamic environment-capture");
2926+
} else {
2927+
// This was an attempt to use a type parameter outside
2928+
// its scope.
2929+
2930+
self.session.span_err(span,
2931+
~"attempt to use a type \
2932+
argument out of scope");
2933+
}
2934+
2935+
ret none;
2936+
}
2937+
}
2938+
}
28942939
OpaqueFunctionRibKind {
28952940
if !is_ty_param {
28962941
// This was an attempt to access an upvar inside a
@@ -3029,7 +3074,7 @@ class Resolver {
30293074
(HasTypeParameters(&ty_m.tps,
30303075
item.id,
30313076
type_parameters.len(),
3032-
NormalRibKind)) {
3077+
MethodRibKind(item.id, Required))) {
30333078

30343079
// Resolve the method-specific type
30353080
// parameters.
@@ -3044,7 +3089,8 @@ class Resolver {
30443089
}
30453090
}
30463091
provided(m) {
3047-
self.resolve_method(NormalRibKind,
3092+
self.resolve_method(MethodRibKind(item.id,
3093+
Provided(m.id)),
30483094
m,
30493095
type_parameters.len(),
30503096
visitor)
@@ -3148,9 +3194,15 @@ class Resolver {
31483194
for (*type_parameters).eachi |index, type_parameter| {
31493195
let name =
31503196
(*self.atom_table).intern(type_parameter.ident);
3197+
#debug("with_type_parameter_rib: %d %d", node_id,
3198+
type_parameter.id);
31513199
let def_like = dl_def(def_ty_param
31523200
(local_def(type_parameter.id),
31533201
index + initial_index));
3202+
// Associate this type parameter with
3203+
// the item that bound it
3204+
self.record_def(type_parameter.id,
3205+
def_typaram_binder(node_id));
31543206
(*function_type_rib).bindings.insert(name, def_like);
31553207
}
31563208
}
@@ -3332,7 +3384,8 @@ class Resolver {
33323384
for class_members.each |class_member| {
33333385
alt class_member.node {
33343386
class_method(method) {
3335-
self.resolve_method(NormalRibKind,
3387+
self.resolve_method(MethodRibKind(id,
3388+
Provided(method.id)),
33363389
method,
33373390
outer_type_parameter_count,
33383391
visitor);
@@ -3451,7 +3504,7 @@ class Resolver {
34513504
// type parameters.
34523505

34533506
let borrowed_type_parameters = &method.tps;
3454-
self.resolve_function(NormalRibKind,
3507+
self.resolve_function(MethodRibKind(id, Provided(method.id)),
34553508
some(@method.decl),
34563509
HasTypeParameters
34573510
(borrowed_type_parameters,

src/rustc/middle/typeck/check.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,6 +2186,10 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
21862186
ast::def_region(*) {
21872187
fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found region");
21882188
}
2189+
ast::def_typaram_binder(*) {
2190+
fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found type \
2191+
parameter");
2192+
}
21892193
}
21902194
}
21912195

src/rustc/middle/typeck/check/regionmanip.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region {
200200
ast::def_foreign_mod(_) | ast::def_const(_) |
201201
ast::def_use(_) | ast::def_variant(_, _) |
202202
ast::def_ty(_) | ast::def_prim_ty(_) |
203-
ast::def_ty_param(_, _) | ast::def_class(_, _) |
204-
ast::def_region(_) {
203+
ast::def_ty_param(_, _) | ast::def_typaram_binder(*) |
204+
ast::def_class(_, _) | ast::def_region(_) {
205205
ty::re_static
206206
}
207207
}

src/test/compile-fail/issue-3021-b.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use std;
2+
3+
fn siphash(k0 : u64) {
4+
5+
class siphash {
6+
let mut v0: u64;
7+
fn reset() {
8+
self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR attempted dynamic environment-capture
9+
//~^ ERROR unresolved name: k0
10+
}
11+
new() { self.v0 = 0; }
12+
}
13+
}
14+
15+
fn main() {}

src/test/compile-fail/issue-3021-c.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use std;
2+
3+
fn siphash<T>() {
4+
5+
trait t {
6+
fn g(x: T) -> T; //~ ERROR attempt to use a type argument out of scope
7+
//~^ ERROR attempt to use a type argument out of scope
8+
//~^^ ERROR use of undeclared type name `T`
9+
//~^^^ ERROR use of undeclared type name `T`
10+
}
11+
}
12+
13+
fn main() {}

src/test/compile-fail/issue-3021-d.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use std;
2+
3+
iface siphash {
4+
fn result() -> u64;
5+
fn reset();
6+
}
7+
8+
fn siphash(k0 : u64, k1 : u64) -> siphash {
9+
type sipstate = {
10+
mut v0 : u64,
11+
mut v1 : u64,
12+
};
13+
14+
fn mk_result(st : sipstate) -> u64 {
15+
16+
let v0 = st.v0,
17+
v1 = st.v1;
18+
ret v0 ^ v1;
19+
}
20+
21+
impl of siphash for sipstate {
22+
fn reset() {
23+
self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR attempted dynamic environment-capture
24+
//~^ ERROR unresolved name: k0
25+
self.v1 = k1 ^ 0x646f72616e646f6d; //~ ERROR attempted dynamic environment-capture
26+
//~^ ERROR unresolved name: k1
27+
}
28+
fn result() -> u64 { ret mk_result(self); }
29+
}
30+
}
31+
32+
fn main() {}

src/test/compile-fail/issue-3021.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use std;
2+
3+
iface siphash {
4+
fn reset();
5+
}
6+
7+
fn siphash(k0 : u64) -> siphash {
8+
type sipstate = {
9+
mut v0 : u64,
10+
};
11+
12+
13+
impl of siphash for sipstate {
14+
fn reset() {
15+
self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR attempted dynamic environment-capture
16+
//~^ ERROR unresolved name: k0
17+
}
18+
}
19+
fail;
20+
}
21+
22+
fn main() {}

0 commit comments

Comments
 (0)