about summary refs log tree commit diff
path: root/src/comp/middle/fn_usage.rs
blob: 1bf9533f0803cd9074a5409dc0ffc44175d7195a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import syntax::ast;
import syntax::visit;
import option::some;
import syntax::print::pprust::expr_to_str;

export check_crate_fn_usage;

type fn_usage_ctx = {
    tcx: ty::ctxt,
    unsafe_fn_legal: bool,
    generic_bare_fn_legal: bool
};

fn fn_usage_expr(expr: @ast::expr,
                 ctx: fn_usage_ctx,
                 v: visit::vt<fn_usage_ctx>) {
    alt expr.node {
      ast::expr_path(path) {
        if !ctx.unsafe_fn_legal {
            alt ctx.tcx.def_map.find(expr.id) {
              some(ast::def_fn(_, ast::unsafe_fn.)) |
              some(ast::def_native_fn(_, ast::unsafe_fn.)) {
                log_err ("expr=", expr_to_str(expr));
                ctx.tcx.sess.span_fatal(
                    expr.span,
                    "unsafe functions can only be called");
              }

              _ {}
            }
        }
        if !ctx.generic_bare_fn_legal
            && ty::expr_has_ty_params(ctx.tcx, expr) {
            alt ty::struct(ctx.tcx, ty::expr_ty(ctx.tcx, expr)) {
              ty::ty_fn(ast::proto_bare., _, _, _, _) {
                ctx.tcx.sess.span_fatal(
                    expr.span,
                    "generic bare functions can only be called or bound");
              }
              _ { }
            }
        }
      }

      ast::expr_call(f, args, _) {
        let f_ctx = {unsafe_fn_legal: true,
                     generic_bare_fn_legal: true with ctx};
        v.visit_expr(f, f_ctx, v);

        let args_ctx = {unsafe_fn_legal: false,
                        generic_bare_fn_legal: false with ctx};
        visit::visit_exprs(args, args_ctx, v);
      }

      ast::expr_bind(f, args) {
        let f_ctx = {unsafe_fn_legal: false,
                     generic_bare_fn_legal: true with ctx};
        v.visit_expr(f, f_ctx, v);

        let args_ctx = {unsafe_fn_legal: false,
                        generic_bare_fn_legal: false with ctx};
        for arg in args {
            visit::visit_expr_opt(arg, args_ctx, v);
        }
      }

      _ {
        let subctx = {unsafe_fn_legal: false,
                      generic_bare_fn_legal: false with ctx};
        visit::visit_expr(expr, subctx, v);
      }
    }
}

fn check_crate_fn_usage(tcx: ty::ctxt, crate: @ast::crate) {
    let visit =
        visit::mk_vt(
            @{visit_expr: fn_usage_expr
                  with *visit::default_visitor()});
    let ctx = {
        tcx: tcx,
        unsafe_fn_legal: false,
        generic_bare_fn_legal: false
    };
    visit::visit_crate(*crate, ctx, visit);
}


// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End: