]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #8797 : nikomatsakis/rust/issue-8625-assign-to-andmut-in-borrowed-loc...
authorbors <bors@rust-lang.org>
Wed, 28 Aug 2013 00:05:46 +0000 (17:05 -0700)
committerbors <bors@rust-lang.org>
Wed, 28 Aug 2013 00:05:46 +0000 (17:05 -0700)
Fixes for #8625 to prevent assigning to `&mut` in borrowed or aliasable locations. The old code was insufficient in that it failed to catch bizarre cases like `& &mut &mut`.

r? @pnkfelix

1  2 
src/librustc/middle/astencode.rs
src/librustc/middle/borrowck/check_loans.rs
src/librustc/middle/moves.rs
src/librustc/middle/resolve.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/typeck/check/mod.rs

index a22daac90b5517e7c30fb48ef77850a7f6cb54a3,c9727db3f5bca543ad22ea57624a15cd97156c6c..857579b5bf025ff8a169c7c6bc9517993f0d51e5
@@@ -383,7 -383,7 +383,7 @@@ impl tr for ast::def 
              ast::def_method(did0.tr(xcx), did1.map(|did1| did1.tr(xcx)))
            }
            ast::def_self_ty(nid) => { ast::def_self_ty(xcx.tr_id(nid)) }
-           ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) }
+           ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) }
            ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }
            ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) }
            ast::def_static(did, m) => { ast::def_static(did.tr(xcx), m) }
@@@ -586,13 -586,8 +586,13 @@@ impl tr for method_origin 
                  }
              )
            }
 -          typeck::method_trait(did, m) => {
 -              typeck::method_trait(did.tr(xcx), m)
 +          typeck::method_object(ref mo) => {
 +            typeck::method_object(
 +                typeck::method_object {
 +                    trait_id: mo.trait_id.tr(xcx),
 +                    .. *mo
 +                }
 +            )
            }
          }
      }
index 0fa7750afa7aadc2367740dc6f6fa2190ef687ee,df918caac373e4a45bb3e9fcec7f0bca2a2e8dbc..4991f75dc3e371ccb71e95f4c1cc8991d2c67cb4
@@@ -27,8 -27,7 +27,8 @@@ use syntax::ast::{m_mutbl, m_imm, m_con
  use syntax::ast;
  use syntax::ast_util;
  use syntax::codemap::span;
 -use syntax::oldvisit;
 +use syntax::visit;
 +use syntax::visit::Visitor;
  use util::ppaux::Repr;
  
  #[deriving(Clone)]
@@@ -40,27 -39,6 +40,27 @@@ struct CheckLoanCtxt<'self> 
      reported: @mut HashSet<ast::NodeId>,
  }
  
 +struct CheckLoanVisitor;
 +
 +impl<'self> Visitor<CheckLoanCtxt<'self>> for CheckLoanVisitor {
 +    fn visit_expr<'a>(&mut self, ex:@ast::expr, e:CheckLoanCtxt<'a>) {
 +        check_loans_in_expr(self, ex, e);
 +    }
 +    fn visit_local(&mut self, l:@ast::Local, e:CheckLoanCtxt) {
 +        check_loans_in_local(self, l, e);
 +    }
 +    fn visit_block(&mut self, b:&ast::Block, e:CheckLoanCtxt) {
 +        check_loans_in_block(self, b, e);
 +    }
 +    fn visit_pat(&mut self, p:@ast::pat, e:CheckLoanCtxt) {
 +        check_loans_in_pat(self, p, e);
 +    }
 +    fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
 +                b:&ast::Block, s:span, n:ast::NodeId, e:CheckLoanCtxt) {
 +        check_loans_in_fn(self, fk, fd, b, s, n, e);
 +    }
 +}
 +
  pub fn check_loans(bccx: @BorrowckCtxt,
                     dfcx_loans: &LoanDataFlow,
                     move_data: move_data::FlowedMoveData,
          reported: @mut HashSet::new(),
      };
  
 -    let vt = oldvisit::mk_vt(@oldvisit::Visitor {
 -        visit_expr: check_loans_in_expr,
 -        visit_local: check_loans_in_local,
 -        visit_block: check_loans_in_block,
 -        visit_pat: check_loans_in_pat,
 -        visit_fn: check_loans_in_fn,
 -        .. *oldvisit::default_visitor()
 -    });
 -    (vt.visit_block)(body, (clcx, vt));
 +    let mut vt = CheckLoanVisitor;
 +    vt.visit_block(body, clcx);
  }
  
  enum MoveError {
@@@ -367,7 -352,6 +367,6 @@@ impl<'self> CheckLoanCtxt<'self> 
  
                      mc::cat_rvalue(*) |
                      mc::cat_static_item |
-                     mc::cat_implicit_self |
                      mc::cat_copied_upvar(*) |
                      mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
                      mc::cat_deref(_, _, mc::gc_ptr(*)) |
                  mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) => {
                      // Statically prohibit writes to `&mut` when aliasable
  
-                     match b.freely_aliasable() {
-                         None => {}
-                         Some(cause) => {
-                             this.bccx.report_aliasability_violation(
-                                 expr.span,
-                                 MutabilityViolation,
-                                 cause);
-                         }
-                     }
+                     check_for_aliasability_violation(this, expr, b);
                  }
  
                  mc::cat_deref(_, deref_count, mc::gc_ptr(ast::m_mutbl)) => {
              return true; // no errors reported
          }
  
+         fn check_for_aliasability_violation(this: &CheckLoanCtxt,
+                                             expr: @ast::expr,
+                                             cmt: mc::cmt) -> bool {
+             let mut cmt = cmt;
+             loop {
+                 match cmt.cat {
+                     mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) |
+                     mc::cat_downcast(b) |
+                     mc::cat_stack_upvar(b) |
+                     mc::cat_deref(b, _, mc::uniq_ptr) |
+                     mc::cat_interior(b, _) |
+                     mc::cat_discr(b, _) => {
+                         // Aliasability depends on base cmt
+                         cmt = b;
+                     }
+                     mc::cat_copied_upvar(_) |
+                     mc::cat_rvalue(*) |
+                     mc::cat_local(*) |
+                     mc::cat_arg(_) |
+                     mc::cat_self(*) |
+                     mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
+                     mc::cat_static_item(*) |
+                     mc::cat_deref(_, _, mc::gc_ptr(_)) |
+                     mc::cat_deref(_, _, mc::region_ptr(m_const, _)) |
+                     mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) => {
+                         // Aliasability is independent of base cmt
+                         match cmt.freely_aliasable() {
+                             None => {
+                                 return true;
+                             }
+                             Some(cause) => {
+                                 this.bccx.report_aliasability_violation(
+                                     expr.span,
+                                     MutabilityViolation,
+                                     cause);
+                                 return false;
+                             }
+                         }
+                     }
+                 }
+             }
+         }
          fn check_for_assignment_to_restricted_or_frozen_location(
              this: &CheckLoanCtxt,
              expr: @ast::expr,
              // path, and check that the super path was not lent out as
              // mutable or immutable (a const loan is ok).
              //
+             // Mutability of a path can be dependent on the super path
+             // in two ways. First, it might be inherited mutability.
+             // Second, the pointee of an `&mut` pointer can only be
+             // mutated if it is found in an unaliased location, so we
+             // have to check that the owner location is not borrowed.
+             //
              // Note that we are *not* checking for any and all
              // restrictions.  We are only interested in the pointers
              // that the user created, whereas we add restrictions for
              let mut loan_path = loan_path;
              loop {
                  match *loan_path {
-                     // Peel back one layer if `loan_path` has
-                     // inherited mutability
-                     LpExtend(lp_base, mc::McInherited, _) => {
+                     // Peel back one layer if, for `loan_path` to be
+                     // mutable, `lp_base` must be mutable. This occurs
+                     // with inherited mutability and with `&mut`
+                     // pointers.
+                     LpExtend(lp_base, mc::McInherited, _) |
+                     LpExtend(lp_base, _, LpDeref(mc::region_ptr(ast::m_mutbl, _))) => {
                          loan_path = lp_base;
                      }
  
      }
  }
  
 -fn check_loans_in_fn<'a>(fk: &oldvisit::fn_kind,
 +fn check_loans_in_fn<'a>(visitor: &mut CheckLoanVisitor,
 +                         fk: &visit::fn_kind,
                           decl: &ast::fn_decl,
                           body: &ast::Block,
                           sp: span,
                           id: ast::NodeId,
 -                         (this, visitor): (CheckLoanCtxt<'a>,
 -                                           oldvisit::vt<CheckLoanCtxt<'a>>)) {
 +                         this: CheckLoanCtxt<'a>) {
      match *fk {
 -        oldvisit::fk_item_fn(*) |
 -        oldvisit::fk_method(*) => {
 +        visit::fk_item_fn(*) |
 +        visit::fk_method(*) => {
              // Don't process nested items.
              return;
          }
  
 -        oldvisit::fk_anon(*) |
 -        oldvisit::fk_fn_block(*) => {
 +        visit::fk_anon(*) |
 +        visit::fk_fn_block(*) => {
              check_captured_variables(this, id, sp);
          }
      }
  
 -    oldvisit::visit_fn(fk, decl, body, sp, id, (this, visitor));
 +    visit::walk_fn(visitor, fk, decl, body, sp, id, this);
  
      fn check_captured_variables(this: CheckLoanCtxt,
                                  closure_id: ast::NodeId,
      }
  }
  
 -fn check_loans_in_local<'a>(local: @ast::Local,
 -                            (this, vt): (CheckLoanCtxt<'a>,
 -                                         oldvisit::vt<CheckLoanCtxt<'a>>)) {
 -    oldvisit::visit_local(local, (this, vt));
 +fn check_loans_in_local<'a>(vt: &mut CheckLoanVisitor,
 +                            local: @ast::Local,
 +                            this: CheckLoanCtxt<'a>) {
 +    visit::walk_local(vt, local, this);
  }
  
 -fn check_loans_in_expr<'a>(expr: @ast::expr,
 -                           (this, vt): (CheckLoanCtxt<'a>,
 -                                        oldvisit::vt<CheckLoanCtxt<'a>>)) {
 -    oldvisit::visit_expr(expr, (this, vt));
 +fn check_loans_in_expr<'a>(vt: &mut CheckLoanVisitor,
 +                           expr: @ast::expr,
 +                           this: CheckLoanCtxt<'a>) {
 +    visit::walk_expr(vt, expr, this);
  
      debug!("check_loans_in_expr(expr=%s)",
             expr.repr(this.tcx()));
      }
  }
  
 -fn check_loans_in_pat<'a>(pat: @ast::pat,
 -                          (this, vt): (CheckLoanCtxt<'a>,
 -                                       oldvisit::vt<CheckLoanCtxt<'a>>))
 +fn check_loans_in_pat<'a>(vt: &mut CheckLoanVisitor,
 +                          pat: @ast::pat,
 +                          this: CheckLoanCtxt<'a>)
  {
      this.check_for_conflicting_loans(pat.id);
      this.check_move_out_from_id(pat.id, pat.span);
 -    oldvisit::visit_pat(pat, (this, vt));
 +    visit::walk_pat(vt, pat, this);
  }
  
 -fn check_loans_in_block<'a>(blk: &ast::Block,
 -                            (this, vt): (CheckLoanCtxt<'a>,
 -                                         oldvisit::vt<CheckLoanCtxt<'a>>))
 +fn check_loans_in_block<'a>(vt: &mut CheckLoanVisitor,
 +                            blk: &ast::Block,
 +                            this: CheckLoanCtxt<'a>)
  {
 -    oldvisit::visit_block(blk, (this, vt));
 +    visit::walk_block(vt, blk, this);
      this.check_for_conflicting_loans(blk.id);
  }
index 7b3fad0b36b2212f528e6871665e6f7052e76db5,ebd9b2b2223442cbfbadd2bb4c7a49ddeb7f476f..9f55e5e3509bcde0319aabc9f7fe12e8f06f7aef
@@@ -139,8 -139,8 +139,8 @@@ use std::at_vec
  use std::hashmap::{HashSet, HashMap};
  use syntax::ast::*;
  use syntax::ast_util;
 -use syntax::oldvisit;
 -use syntax::oldvisit::vt;
 +use syntax::visit;
 +use syntax::visit::Visitor;
  use syntax::codemap::span;
  
  #[deriving(Encodable, Decodable)]
@@@ -190,26 -190,16 +190,26 @@@ enum UseMode 
      Read         // Read no matter what the type.
  }
  
 +struct ComputeModesVisitor;
 +
 +impl visit::Visitor<VisitContext> for ComputeModesVisitor {
 +    fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&fn_decl,
 +                b:&Block, s:span, n:NodeId, e:VisitContext) {
 +        compute_modes_for_fn(*self, fk, fd, b, s, n, e);
 +    }
 +    fn visit_expr(&mut self, ex:@expr, e:VisitContext) {
 +        compute_modes_for_expr(*self, ex, e);
 +    }
 +    fn visit_local(&mut self, l:@Local, e:VisitContext) {
 +        compute_modes_for_local(*self, l, e);
 +    }
 +}
 +
  pub fn compute_moves(tcx: ty::ctxt,
                       method_map: method_map,
                       crate: &Crate) -> MoveMaps
  {
 -    let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
 -        visit_fn: compute_modes_for_fn,
 -        visit_expr: compute_modes_for_expr,
 -        visit_local: compute_modes_for_local,
 -        .. *oldvisit::default_visitor()
 -    });
 +    let mut visitor = ComputeModesVisitor;
      let visit_cx = VisitContext {
          tcx: tcx,
          method_map: method_map,
              moved_variables_set: @mut HashSet::new()
          }
      };
 -    oldvisit::visit_crate(crate, (visit_cx, visitor));
 +    visit::walk_crate(&mut visitor, crate, visit_cx);
      return visit_cx.move_maps;
  }
  
@@@ -228,7 -218,7 +228,7 @@@ pub fn moved_variable_node_id_from_def(
        def_binding(nid, _) |
        def_arg(nid, _) |
        def_local(nid, _) |
-       def_self(nid, _) => Some(nid),
+       def_self(nid) => Some(nid),
  
        _ => None
      }
  ///////////////////////////////////////////////////////////////////////////
  // Expressions
  
 -fn compute_modes_for_local<'a>(local: @Local,
 -                               (cx, v): (VisitContext,
 -                                         vt<VisitContext>)) {
 +fn compute_modes_for_local<'a>(v: ComputeModesVisitor,
 +                               local: @Local,
 +                               cx: VisitContext) {
      cx.use_pat(local.pat);
      for &init in local.init.iter() {
          cx.use_expr(init, Read, v);
      }
  }
  
 -fn compute_modes_for_fn(fk: &oldvisit::fn_kind,
 +fn compute_modes_for_fn(v: ComputeModesVisitor,
 +                        fk: &visit::fn_kind,
                          decl: &fn_decl,
                          body: &Block,
                          span: span,
                          id: NodeId,
 -                        (cx, v): (VisitContext,
 -                                  vt<VisitContext>)) {
 +                        cx: VisitContext) {
 +    let mut v = v;
      for a in decl.inputs.iter() {
          cx.use_pat(a.pat);
      }
 -    oldvisit::visit_fn(fk, decl, body, span, id, (cx, v));
 +    visit::walk_fn(&mut v, fk, decl, body, span, id, cx);
  }
  
 -fn compute_modes_for_expr(expr: @expr,
 -                          (cx, v): (VisitContext,
 -                                    vt<VisitContext>))
 +fn compute_modes_for_expr(v: ComputeModesVisitor,
 +                          expr: @expr,
 +                          cx: VisitContext)
  {
      cx.consume_expr(expr, v);
  }
  
  impl VisitContext {
 -    pub fn consume_exprs(&self, exprs: &[@expr], visitor: vt<VisitContext>) {
 +    pub fn consume_exprs(&self, exprs: &[@expr], visitor: ComputeModesVisitor) {
          for expr in exprs.iter() {
              self.consume_expr(*expr, visitor);
          }
      }
  
 -    pub fn consume_expr(&self, expr: @expr, visitor: vt<VisitContext>) {
 +    pub fn consume_expr(&self, expr: @expr, visitor: ComputeModesVisitor) {
          /*!
           * Indicates that the value of `expr` will be consumed,
           * meaning either copied or moved depending on its type.
          };
      }
  
 -    pub fn consume_block(&self, blk: &Block, visitor: vt<VisitContext>) {
 +    pub fn consume_block(&self, blk: &Block, visitor: ComputeModesVisitor) {
          /*!
           * Indicates that the value of `blk` will be consumed,
           * meaning either copied or moved depending on its type.
          debug!("consume_block(blk.id=%?)", blk.id);
  
          for stmt in blk.stmts.iter() {
 -            (visitor.visit_stmt)(*stmt, (*self, visitor));
 +            let mut v = visitor;
 +            v.visit_stmt(*stmt, *self);
          }
  
          for tail_expr in blk.expr.iter() {
      pub fn use_expr(&self,
                      expr: @expr,
                      expr_mode: UseMode,
 -                    visitor: vt<VisitContext>) {
 +                    visitor: ComputeModesVisitor) {
          /*!
           * Indicates that `expr` is used with a given mode.  This will
           * in turn trigger calls to the subcomponents of `expr`.
                                     expr: &expr,
                                     receiver_expr: @expr,
                                     arg_exprs: &[@expr],
 -                                   visitor: vt<VisitContext>)
 +                                   visitor: ComputeModesVisitor)
                                     -> bool {
          if !self.method_map.contains_key(&expr.id) {
              return false;
          return true;
      }
  
 -    pub fn consume_arm(&self, arm: &arm, visitor: vt<VisitContext>) {
 +    pub fn consume_arm(&self, arm: &arm, visitor: ComputeModesVisitor) {
          for pat in arm.pats.iter() {
              self.use_pat(*pat);
          }
  
      pub fn use_receiver(&self,
                          receiver_expr: @expr,
 -                        visitor: vt<VisitContext>) {
 +                        visitor: ComputeModesVisitor) {
          self.use_fn_arg(receiver_expr, visitor);
      }
  
      pub fn use_fn_args(&self,
                         _: NodeId,
                         arg_exprs: &[@expr],
 -                       visitor: vt<VisitContext>) {
 +                       visitor: ComputeModesVisitor) {
          //! Uses the argument expressions.
          for arg_expr in arg_exprs.iter() {
              self.use_fn_arg(*arg_expr, visitor);
          }
      }
  
 -    pub fn use_fn_arg(&self, arg_expr: @expr, visitor: vt<VisitContext>) {
 +    pub fn use_fn_arg(&self, arg_expr: @expr, visitor: ComputeModesVisitor) {
          //! Uses the argument.
          self.consume_expr(arg_expr, visitor)
      }
index 0dee86e2a196cd07b85e40aca6c8cff4f3a53675,351f4f8277a02eb4f628c981e096da78ca159e1f..d60d1e2b8450c3681ab26a8989aab99614ad5274
@@@ -125,7 -125,7 +125,7 @@@ pub enum Mutability 
  
  pub enum SelfBinding {
      NoSelfBinding,
-     HasSelfBinding(NodeId, bool /* is implicit */)
+     HasSelfBinding(NodeId)
  }
  
  struct ResolveVisitor {
@@@ -831,7 -831,6 +831,7 @@@ pub fn Resolver(session: Session
          trait_map: HashMap::new(),
          used_imports: HashSet::new(),
  
 +        emit_errors: true,
          intr: session.intr()
      };
  
@@@ -889,11 -888,6 +889,11 @@@ pub struct Resolver 
      export_map2: ExportMap2,
      trait_map: TraitMap,
  
 +    // Whether or not to print error messages. Can be set to true
 +    // when getting additional info for error message suggestions,
 +    // so as to avoid printing duplicate errors
 +    emit_errors: bool,
 +
      used_imports: HashSet<NodeId>,
  }
  
@@@ -1078,7 -1072,7 +1078,7 @@@ impl Resolver 
                      // Return an error here by looking up the namespace that
                      // had the duplicate.
                      let ns = ns.unwrap();
 -                    self.session.span_err(sp,
 +                    self.resolve_error(sp,
                          fmt!("duplicate definition of %s `%s`",
                               namespace_error_to_str(duplicate_type),
                               self.session.str_of(name)));
                                     self.import_path_to_str(
                                         import_directive.module_path,
                                         *import_directive.subclass));
 -                    self.session.span_err(import_directive.span, msg);
 +                    self.resolve_error(import_directive.span, msg);
                  }
                  Indeterminate => {
                      // Bail out. We'll come around next time.
  
          // We need to resolve both namespaces for this to succeed.
          //
 -        // FIXME #4949: See if there's some way of handling namespaces in
 -        // a more generic way. We have two of them; it seems worth
 -        // doing...
  
          let mut value_result = UnknownResult;
          let mut type_result = UnknownResult;
  
          let span = directive.span;
          if resolve_fail {
 -            self.session.span_err(span, fmt!("unresolved import: there is no `%s` in `%s`",
 +            self.resolve_error(span, fmt!("unresolved import: there is no `%s` in `%s`",
                                               self.session.str_of(source),
                                               self.module_to_str(containing_module)));
              return Failed;
          } else if priv_fail {
 -            self.session.span_err(span, fmt!("unresolved import: found `%s` in `%s` but it is \
 +            self.resolve_error(span, fmt!("unresolved import: found `%s` in `%s` but it is \
                                               private", self.session.str_of(source),
                                               self.module_to_str(containing_module)));
              return Failed;
                              hi: span.lo + BytePos(segment_name.len()),
                              expn_info: span.expn_info,
                          };
 -                        self.session.span_err(span,
 +                        self.resolve_error(span,
                                                fmt!("unresolved import. maybe \
                                                      a missing `extern mod \
                                                      %s`?",
                                                      segment_name));
                          return Failed;
                      }
 -                    self.session.span_err(span, fmt!("unresolved import: could not find `%s` in \
 +                    self.resolve_error(span, fmt!("unresolved import: could not find `%s` in \
                                                       `%s`.", segment_name, module_name));
                      return Failed;
                  }
                              match type_def.module_def {
                                  None => {
                                      // Not a module.
 -                                    self.session.span_err(span,
 +                                    self.resolve_error(span,
                                                            fmt!("not a \
                                                                  module `%s`",
                                                                 self.session.
                                             module_def.kind) {
                                          (ImportSearch, TraitModuleKind) |
                                          (ImportSearch, ImplModuleKind) => {
 -                                            self.session.span_err(
 +                                            self.resolve_error(
                                                  span,
                                                  "cannot import from a trait \
                                                   or type implementation");
                          }
                          None => {
                              // There are no type bindings at all.
 -                            self.session.span_err(span,
 +                            self.resolve_error(span,
                                                    fmt!("not a module `%s`",
                                                         self.session.str_of(
                                                              name)));
                  let mpath = self.idents_to_str(module_path);
                  match mpath.rfind(':') {
                      Some(idx) => {
 -                        self.session.span_err(span, fmt!("unresolved import: could not find `%s` \
 +                        self.resolve_error(span, fmt!("unresolved import: could not find `%s` \
                                                           in `%s`",
                                                           // idx +- 1 to account for the colons
                                                           // on either side
                              module_path[0]);
                          match result {
                              Failed => {
 -                                self.session.span_err(span,
 -                                                      "unresolved name");
 +                                self.resolve_error(span, "unresolved name");
                                  return Failed;
                              }
                              Indeterminate => {
          if index != import_count {
              let sn = self.session.codemap.span_to_snippet(imports[index].span).unwrap();
              if sn.contains("::") {
 -                self.session.span_err(imports[index].span, "unresolved import");
 +                self.resolve_error(imports[index].span, "unresolved import");
              } else {
                  let err = fmt!("unresolved import (maybe you meant `%s::*`?)",
                                 sn.slice(0, sn.len()));
 -                self.session.span_err(imports[index].span, err);
 +                self.resolve_error(imports[index].span, err);
              }
          }
  
                          // named function item. This is not allowed, so we
                          // report an error.
  
 -                        self.session.span_err(
 +                        self.resolve_error(
                              span,
                              "can't capture dynamic environment in a fn item; \
                              use the || { ... } closure form instead");
                          // This was an attempt to use a type parameter outside
                          // its scope.
  
 -                        self.session.span_err(span,
 +                        self.resolve_error(span,
                                                "attempt to use a type \
                                                argument out of scope");
                      }
                          // named function item. This is not allowed, so we
                          // report an error.
  
 -                        self.session.span_err(
 +                        self.resolve_error(
                              span,
                              "can't capture dynamic environment in a fn item; \
                              use the || { ... } closure form instead");
                          // This was an attempt to use a type parameter outside
                          // its scope.
  
 -                        self.session.span_err(span,
 +                        self.resolve_error(span,
                                                "attempt to use a type \
                                                argument out of scope");
                      }
                  }
                  ConstantItemRibKind => {
                      // Still doesn't deal with upvars
 -                    self.session.span_err(span,
 +                    self.resolve_error(span,
                                            "attempt to use a non-constant \
                                             value in a constant");
  
                  NoSelfBinding => {
                      // Nothing to do.
                  }
-                 HasSelfBinding(self_node_id, is_implicit) => {
-                     let def_like = dl_def(def_self(self_node_id,
-                                                    is_implicit));
+                 HasSelfBinding(self_node_id) => {
+                     let def_like = dl_def(def_self(self_node_id));
                      *function_value_rib.self_binding = Some(def_like);
                  }
              }
                  };
  
                  let msg = fmt!("attempt to %s a nonexistent trait `%s`", usage_str, path_str);
 -                self.session.span_err(trait_reference.path.span, msg);
 +                self.resolve_error(trait_reference.path.span, msg);
              }
              Some(def) => {
                  debug!("(resolving trait) found trait def: %?", def);
                      match ident_map.find(&ident) {
                          Some(&prev_field) => {
                              let ident_str = self.session.str_of(ident);
 -                            self.session.span_err(field.span,
 +                            self.resolve_error(field.span,
                                  fmt!("field `%s` is already declared", ident_str));
                              self.session.span_note(prev_field.span,
                                  "Previously declared here");
          // we only have self ty if it is a non static method
          let self_binding = match method.explicit_self.node {
            sty_static => { NoSelfBinding }
-           _ => { HasSelfBinding(method.self_id, false) }
+           _ => { HasSelfBinding(method.self_id) }
          };
  
          self.resolve_function(rib_kind,
              for (&key, &binding_0) in map_0.iter() {
                  match map_i.find(&key) {
                    None => {
 -                    self.session.span_err(
 +                    self.resolve_error(
                          p.span,
                          fmt!("variable `%s` from pattern #1 is \
                                    not bound in pattern #%u",
                    }
                    Some(binding_i) => {
                      if binding_0.binding_mode != binding_i.binding_mode {
 -                        self.session.span_err(
 +                        self.resolve_error(
                              binding_i.span,
                              fmt!("variable `%s` is bound with different \
                                        mode in pattern #%u than in pattern #1",
  
              for (&key, &binding) in map_i.iter() {
                  if !map_0.contains_key(&key) {
 -                    self.session.span_err(
 +                    self.resolve_error(
                          binding.span,
                          fmt!("variable `%s` from pattern #%u is \
                                    not bound in pattern #1",
                          self.record_def(path_id, def);
                      }
                      None => {
 -                        self.session.span_err
 +                        self.resolve_error
                              (ty.span, fmt!("use of undeclared type name `%s`",
                                             self.idents_to_str(path.idents)));
                      }
                              self.record_def(pattern.id, def);
                          }
                          FoundStructOrEnumVariant(_) => {
 -                            self.session.span_err(pattern.span,
 +                            self.resolve_error(pattern.span,
                                                    fmt!("declaration of `%s` \
                                                          shadows an enum \
                                                          variant or unit-like \
                              self.record_def(pattern.id, def);
                          }
                          FoundConst(_) => {
 -                            self.session.span_err(pattern.span,
 +                            self.resolve_error(pattern.span,
                                                    "only refutable patterns \
                                                     allowed here");
                          }
                                        // Then this is a duplicate variable
                                        // in the same disjunct, which is an
                                        // error
 -                                     self.session.span_err(pattern.span,
 +                                     self.resolve_error(pattern.span,
                                         fmt!("Identifier `%s` is bound more \
                                               than once in the same pattern",
                                              path_to_str(path, self.session
                              self.record_def(pattern.id, def);
                          }
                          Some(_) => {
 -                            self.session.span_err(
 +                            self.resolve_error(
                                  path.span,
                                  fmt!("`%s` is not an enum variant or constant",
                                       self.session.str_of(
                                           *path.idents.last())));
                          }
                          None => {
 -                            self.session.span_err(path.span,
 +                            self.resolve_error(path.span,
                                                    "unresolved enum variant");
                          }
                      }
                              self.record_def(pattern.id, def);
                          }
                          Some(_) => {
 -                            self.session.span_err(
 +                            self.resolve_error(
                                  path.span,
                                  fmt!("`%s` is not an enum variant, struct or const",
                                       self.session.str_of(
                                           *path.idents.last())));
                          }
                          None => {
 -                            self.session.span_err(path.span,
 +                            self.resolve_error(path.span,
                                                    "unresolved enum variant, \
                                                     struct or const");
                          }
                          result => {
                              debug!("(resolving pattern) didn't find struct \
                                      def: %?", result);
 -                            self.session.span_err(
 +                            self.resolve_error(
                                  path.span,
                                  fmt!("`%s` does not name a structure",
                                       self.idents_to_str(path.idents)));
                                         path.span,
                                         PathPublicOnlySearch) {
              Failed => {
 -                self.session.span_err(path.span,
 +                self.resolve_error(path.span,
                                        fmt!("use of undeclared module `%s`",
                                             self.idents_to_str(
                                                 module_path_idents)));
                                                   path.span,
                                                   PathPublicOrPrivateSearch) {
              Failed => {
 -                self.session.span_err(path.span,
 +                self.resolve_error(path.span,
                                        fmt!("use of undeclared module `::%s`",
                                              self.idents_to_str(
                                                module_path_idents)));
                                          DontAllowCapturingSelf) {
                          Some(dl_def(def)) => return Some(def),
                          _ => {
 -                            self.session.span_bug(span,
 -                                                  "self wasn't mapped to a \
 -                                                   def?!")
 +                            if self.session.has_errors() {
 +                                // May happen inside a nested fn item, cf #6642.
 +                                return None;
 +                            } else {
 +                                self.session.span_bug(span,
 +                                        "self wasn't mapped to a def?!")
 +                            }
                          }
                      }
                  }
          }
      }
  
 +    fn with_no_errors<T>(@mut self, f: &fn() -> T) -> T {
 +        self.emit_errors = false;
 +        let rs = f();
 +        self.emit_errors = true;
 +        rs
 +    }
 +
 +    fn resolve_error(@mut self, span: span, s: &str) {
 +        if self.emit_errors {
 +            self.session.span_err(span, s);
 +        }
 +    }
 +
      pub fn find_best_match_for_name(@mut self,
                                      name: &str,
                                      max_distance: uint)
                          // out here.
                          match def {
                              def_method(*) => {
 -                                self.session.span_err(expr.span,
 +                                self.resolve_error(expr.span,
                                                        "first-class methods \
                                                         are not supported");
                                  self.session.span_note(expr.span,
                          let wrong_name = self.idents_to_str(
                              path.idents);
                          if self.name_exists_in_scope_struct(wrong_name) {
 -                            self.session.span_err(expr.span,
 +                            self.resolve_error(expr.span,
                                          fmt!("unresolved name `%s`. \
                                              Did you mean `self.%s`?",
                                          wrong_name,
                                          wrong_name));
                          }
                          else {
 -                            // limit search to 5 to reduce the number
 -                            // of stupid suggestions
 -                            match self.find_best_match_for_name(wrong_name, 5) {
 -                                Some(m) => {
 -                                    self.session.span_err(expr.span,
 -                                            fmt!("unresolved name `%s`. \
 -                                                Did you mean `%s`?",
 -                                                wrong_name, m));
 -                                }
 -                                None => {
 -                                    self.session.span_err(expr.span,
 -                                            fmt!("unresolved name `%s`.",
 -                                                wrong_name));
 +                            // Be helpful if the name refers to a struct
 +                            // (The pattern matching def_tys where the id is in self.structs
 +                            // matches on regular structs while excluding tuple- and enum-like
 +                            // structs, which wouldn't result in this error.)
 +                            match self.with_no_errors(||
 +                                self.resolve_path(expr.id, path, TypeNS, false, visitor)) {
 +                                Some(def_ty(struct_id))
 +                                  if self.structs.contains(&struct_id) => {
 +                                    self.resolve_error(expr.span,
 +                                            fmt!("`%s` is a structure name, but this expression \
 +                                                uses it like a function name", wrong_name));
 +
 +                                    self.session.span_note(expr.span, fmt!("Did you mean to write: \
 +                                                `%s { /* fields */ }`?", wrong_name));
 +
                                  }
 +                                _ =>
 +                                   // limit search to 5 to reduce the number
 +                                   // of stupid suggestions
 +                                   match self.find_best_match_for_name(wrong_name, 5) {
 +                                       Some(m) => {
 +                                           self.resolve_error(expr.span,
 +                                               fmt!("unresolved name `%s`. \
 +                                                   Did you mean `%s`?",
 +                                                   wrong_name, m));
 +                                       }
 +                                       None => {
 +                                           self.resolve_error(expr.span,
 +                                                fmt!("unresolved name `%s`.",
 +                                                    wrong_name));
 +                                       }
 +                                   }
                              }
                          }
                      }
                      result => {
                          debug!("(resolving expression) didn't find struct \
                                  def: %?", result);
 -                        self.session.span_err(
 +                        self.resolve_error(
                              path.span,
                              fmt!("`%s` does not name a structure",
                                   self.idents_to_str(path.idents)));
                  match self.search_ribs(self.label_ribs, label, expr.span,
                                         DontAllowCapturingSelf) {
                      None =>
 -                        self.session.span_err(expr.span,
 +                        self.resolve_error(expr.span,
                                                fmt!("use of undeclared label \
                                                     `%s`",
                                                     self.session.str_of(
              expr_self => {
                  match self.resolve_self_value_in_local_ribs(expr.span) {
                      None => {
 -                        self.session.span_err(expr.span,
 +                        self.resolve_error(expr.span,
                                                "`self` is not allowed in \
                                                 this context")
                      }
          match pat_binding_mode {
              bind_infer => {}
              bind_by_ref(*) => {
 -                self.session.span_err(
 +                self.resolve_error(
                      pat.span,
                      fmt!("cannot use `ref` binding mode with %s",
                           descr));
index 06c45e563c0da36622e7671e90ce5aa7d1de8251,4b31b9123532ce95f91006019185410f610eb364..6f981123f5fc31ee13ed88a923cd2a7f7ea82c0b
@@@ -413,7 -413,7 +413,7 @@@ pub fn trans_into(bcx: @mut Block, expr
             dest.to_str(bcx.ccx()));
      let _indenter = indenter();
  
 -    debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
 +    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
  
      let dest = {
          if ty::type_is_voidish(ty) {
@@@ -485,7 -485,7 +485,7 @@@ fn trans_to_datum_unadjusted(bcx: @mut 
      debug!("trans_to_datum_unadjusted(expr=%s)", bcx.expr_to_str(expr));
      let _indenter = indenter();
  
 -    debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
 +    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
  
      match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) {
          ty::LvalueExpr => {
@@@ -795,18 -795,14 +795,18 @@@ fn trans_def_dps_unadjusted(bcx: @mut B
                  return bcx;
              }
          }
 -        ast::def_struct(*) => {
 +        ast::def_struct(def_id) => {
              let ty = expr_ty(bcx, ref_expr);
              match ty::get(ty).sty {
                  ty::ty_struct(did, _) if ty::has_dtor(ccx.tcx, did) => {
                      let repr = adt::represent_type(ccx, ty);
                      adt::trans_start_init(bcx, repr, lldest, 0);
                  }
 -                _ => {}
 +                ty::ty_bare_fn(*) => {
 +                    let fn_data = callee::trans_fn_ref(bcx, def_id, ref_expr.id);
 +                    Store(bcx, fn_data.llfn, lldest);
 +                }
 +                _ => ()
              }
              return bcx;
          }
@@@ -824,30 -820,56 +824,30 @@@ fn trans_def_datum_unadjusted(bcx: @mu
  {
      let _icx = push_ctxt("trans_def_datum_unadjusted");
  
 -    match def {
 +    let fn_data = match def {
          ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
 -            let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
 -            return fn_data_to_datum(bcx, ref_expr, did, fn_data);
 +            callee::trans_fn_ref(bcx, did, ref_expr.id)
          }
          ast::def_static_method(impl_did, Some(trait_did), _) => {
 -            let fn_data = meth::trans_static_method_callee(bcx, impl_did,
 -                                                           trait_did,
 -                                                           ref_expr.id);
 -            return fn_data_to_datum(bcx, ref_expr, impl_did, fn_data);
 +            meth::trans_static_method_callee(bcx, impl_did,
 +                                             trait_did,
 +                                             ref_expr.id)
          }
          _ => {
              bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
                  "Non-DPS def %? referened by %s",
                  def, bcx.node_id_to_str(ref_expr.id)));
          }
 -    }
 +    };
  
 -    fn fn_data_to_datum(bcx: @mut Block,
 -                        ref_expr: &ast::expr,
 -                        def_id: ast::def_id,
 -                        fn_data: callee::FnData) -> DatumBlock {
 -        /*!
 -        *
 -        * Translates a reference to a top-level fn item into a rust
 -        * value.  This is just a fn pointer.
 -        */
 -
 -        let is_extern = {
 -            let fn_tpt = ty::lookup_item_type(bcx.tcx(), def_id);
 -            ty::ty_fn_purity(fn_tpt.ty) == ast::extern_fn
 -        };
 -        let (rust_ty, llval) = if is_extern {
 -            let rust_ty = ty::mk_ptr(
 -                bcx.tcx(),
 -                ty::mt {
 -                    ty: ty::mk_mach_uint(ast::ty_u8),
 -                    mutbl: ast::m_imm
 -                }); // *u8
 -            (rust_ty, PointerCast(bcx, fn_data.llfn, Type::i8p()))
 -        } else {
 -            let fn_ty = expr_ty(bcx, ref_expr);
 -            (fn_ty, fn_data.llfn)
 -        };
 -        return DatumBlock {
 -            bcx: bcx,
 -            datum: Datum {val: llval,
 -                          ty: rust_ty,
 -                          mode: ByValue}
 -        };
 +    let fn_ty = expr_ty(bcx, ref_expr);
 +    DatumBlock {
 +        bcx: bcx,
 +        datum: Datum {
 +            val: fn_data.llfn,
 +            ty: fn_ty,
 +            mode: ByValue
 +        }
      }
  }
  
@@@ -1066,7 -1088,7 +1066,7 @@@ pub fn trans_local_var(bcx: @mut Block
          ast::def_local(nid, _) | ast::def_binding(nid, _) => {
              take_local(bcx, bcx.fcx.lllocals, nid)
          }
-         ast::def_self(nid, _) => {
+         ast::def_self(nid) => {
              let self_info: ValSelfData = match bcx.fcx.llself {
                  Some(ref self_info) => *self_info,
                  None => {
  pub fn with_field_tys<R>(tcx: ty::ctxt,
                           ty: ty::t,
                           node_id_opt: Option<ast::NodeId>,
 -                         op: &fn(uint, (&[ty::field])) -> R) -> R {
 +                         op: &fn(ty::Disr, (&[ty::field])) -> R) -> R {
      match ty::get(ty).sty {
          ty::ty_struct(did, ref substs) => {
              op(0, struct_fields(tcx, did, substs))
@@@ -1235,7 -1257,7 +1235,7 @@@ struct StructBaseInfo 
   * - `optbase` contains information on the base struct (if any) from
   * which remaining fields are copied; see comments on `StructBaseInfo`.
   */
 -fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: uint,
 +fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: ty::Disr,
               fields: &[(uint, @ast::expr)],
               optbase: Option<StructBaseInfo>,
               dest: Dest) -> @mut Block {
@@@ -1631,7 -1653,6 +1631,7 @@@ pub fn cast_type_kind(t: ty::t) -> cast
          ty::ty_float(*)   => cast_float,
          ty::ty_ptr(*)     => cast_pointer,
          ty::ty_rptr(*)    => cast_pointer,
 +        ty::ty_bare_fn(*) => cast_pointer,
          ty::ty_int(*)     => cast_integral,
          ty::ty_uint(*)    => cast_integral,
          ty::ty_bool       => cast_integral,
@@@ -1694,16 -1715,10 +1694,16 @@@ fn trans_imm_cast(bcx: @mut Block, expr
                                                val_ty(lldiscrim_a),
                                                lldiscrim_a, true),
                      cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
 -                    _ => ccx.sess.bug("translating unsupported cast.")
 +                    _ => ccx.sess.bug(fmt!("translating unsupported cast: \
 +                                           %s (%?) -> %s (%?)",
 +                                           t_in.repr(ccx.tcx), k_in,
 +                                           t_out.repr(ccx.tcx), k_out))
                  }
              }
 -            _ => ccx.sess.bug("translating unsupported cast.")
 +            _ => ccx.sess.bug(fmt!("translating unsupported cast: \
 +                                   %s (%?) -> %s (%?)",
 +                                   t_in.repr(ccx.tcx), k_in,
 +                                   t_out.repr(ccx.tcx), k_out))
          };
      return immediate_rvalue_bcx(bcx, newval, t_out);
  }
index a839ea976e62e60a44481aadac5f2b9a315b8556,8f7d8ac186ee60c1f4d495e3ae2b75f6d952f313..0c8f22294244227cce9c8af3c097d2c6163aed61
@@@ -83,7 -83,7 +83,7 @@@ use middle::pat_util
  use middle::lint::unreachable_code;
  use middle::ty::{FnSig, VariantInfo};
  use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
 -use middle::ty::{substs, param_ty, ExprTyProvider};
 +use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
  use middle::ty;
  use middle::typeck::astconv::AstConv;
  use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
@@@ -3000,8 -3000,8 +3000,8 @@@ pub fn check_enum_variants(ccx: @mut Cr
  
          let rty = ty::node_id_to_type(ccx.tcx, id);
          let mut variants: ~[@ty::VariantInfo] = ~[];
 -        let mut disr_vals: ~[uint] = ~[];
 -        let mut prev_disr_val: Option<uint> = None;
 +        let mut disr_vals: ~[ty::Disr] = ~[];
 +        let mut prev_disr_val: Option<ty::Disr> = None;
  
          for v in vs.iter() {
  
                      // handle, so we may still get an internal compiler error
  
                      match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
 -                        Ok(const_eval::const_int(val)) => current_disr_val = val as uint,
 -                        Ok(const_eval::const_uint(val)) => current_disr_val = val as uint,
 +                        Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
 +                        Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
                          Ok(_) => {
                              ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
                          }
@@@ -3092,12 -3092,29 +3092,12 @@@ pub fn ty_param_bounds_and_ty_for_def(f
                                        sp: span,
                                        defn: ast::def)
                                     -> ty_param_bounds_and_ty {
 -
      match defn {
-       ast::def_arg(nid, _) | ast::def_local(nid, _) | ast::def_self(nid, _) |
+       ast::def_arg(nid, _) | ast::def_local(nid, _) | ast::def_self(nid) |
        ast::def_binding(nid, _) => {
            let typ = fcx.local_ty(sp, nid);
            return no_params(typ);
        }
 -      ast::def_fn(_, ast::extern_fn) => {
 -        // extern functions are just u8 pointers
 -        return ty_param_bounds_and_ty {
 -            generics: ty::Generics {
 -                type_param_defs: @~[],
 -                region_param: None
 -            },
 -            ty: ty::mk_ptr(
 -                fcx.ccx.tcx,
 -                ty::mt {
 -                    ty: ty::mk_mach_uint(ast::ty_u8),
 -                    mutbl: ast::m_imm
 -                })
 -        };
 -      }
 -
        ast::def_fn(id, _) | ast::def_static_method(id, _, _) |
        ast::def_static(id, _) | ast::def_variant(_, id) |
        ast::def_struct(id) => {
@@@ -3148,8 -3165,7 +3148,8 @@@ pub fn instantiate_path(fcx: @mut FnCtx
      let ty_param_count = tpt.generics.type_param_defs.len();
      let ty_substs_len = pth.types.len();
  
 -    debug!("ty_param_count=%? ty_substs_len=%?",
 +    debug!("tpt=%s ty_param_count=%? ty_substs_len=%?",
 +           tpt.repr(fcx.tcx()),
             ty_param_count,
             ty_substs_len);