@@ -505,14 +505,11 @@ enum check_loan_ctxt = @{
505
505
// we are in a ctor, we track the self id
506
506
mut in_ctor: bool ,
507
507
508
- mut is_pure : purity_cause
508
+ mut declared_purity : ast :: purity
509
509
} ;
510
510
511
511
// if we are enforcing purity, why are we doing so?
512
512
enum purity_cause {
513
- // not enforcing purity:
514
- pc_impure,
515
-
516
513
// enforcing purity because fn was declared pure:
517
514
pc_declaration,
518
515
@@ -529,7 +526,7 @@ fn check_loans(bccx: borrowck_ctxt,
529
526
req_maps : req_maps,
530
527
reported : int_hash( ) ,
531
528
mut in_ctor : false ,
532
- mut is_pure : pc_impure } ) ;
529
+ mut declared_purity : ast :: impure_fn } ) ;
533
530
let vt = visit:: mk_vt( @{ visit_expr: check_loans_in_expr,
534
531
visit_block: check_loans_in_block,
535
532
visit_fn: check_loans_in_fn
@@ -556,6 +553,37 @@ impl methods for assignment_type {
556
553
impl methods for check_loan_ctxt {
557
554
fn tcx( ) -> ty:: ctxt { self. bccx. tcx }
558
555
556
+ fn purity( scope_id: ast:: node_id) -> option < purity_cause > {
557
+ let default_purity = alt self . declared_purity {
558
+ // an unsafe declaration overrides all
559
+ ast : : unsafe_fn { ret none; }
560
+
561
+ // otherwise, remember what was declared as the
562
+ // default, but we must scan for requirements
563
+ // imposed by the borrow check
564
+ ast:: pure_fn { some( pc_declaration) }
565
+ ast:: crust_fn | ast:: impure_fn { none }
566
+ } ;
567
+
568
+ // scan to see if this scope or any enclosing scope requires
569
+ // purity. if so, that overrides the declaration.
570
+
571
+ let mut scope_id = scope_id;
572
+ let region_map = self . tcx( ) . region_map;
573
+ let pure_map = self . req_maps. pure_map;
574
+ loop {
575
+ alt pure_map. find( scope_id) {
576
+ none { }
577
+ some( e) { ret some( pc_cmt( e) ) ; }
578
+ }
579
+
580
+ alt region_map. find( scope_id) {
581
+ none { ret default_purity; }
582
+ some( next_scope_id) { scope_id = next_scope_id; }
583
+ }
584
+ }
585
+ }
586
+
559
587
fn walk_loans( scope_id: ast:: node_id,
560
588
f: fn ( loan) -> bool) {
561
589
let mut scope_id = scope_id;
@@ -590,7 +618,7 @@ impl methods for check_loan_ctxt {
590
618
591
619
// when we are in a pure context, we check each call to ensure
592
620
// that the function which is invoked is itself pure.
593
- fn check_pure( expr: @ast:: expr) {
621
+ fn check_pure( pc : purity_cause , expr: @ast:: expr) {
594
622
let tcx = self . tcx( ) ;
595
623
alt ty:: get( tcx. ty( expr) ) . struct {
596
624
ty:: ty_fn( _) {
@@ -645,7 +673,7 @@ impl methods for check_loan_ctxt {
645
673
}
646
674
ast:: impure_fn | ast:: unsafe_fn {
647
675
self. report_purity_error(
648
- expr. span,
676
+ pc , expr. span,
649
677
"access to non-pure functions") ;
650
678
}
651
679
}
@@ -654,21 +682,6 @@ impl methods for check_loan_ctxt {
654
682
}
655
683
}
656
684
657
- fn check_for_purity_requirement( scope_id: ast:: node_id) {
658
- // if we are not already enforcing purity, check whether the
659
- // gather pass thought we needed to enforce purity for this
660
- // scope.
661
- alt self. is_pure {
662
- pc_declaration | pc_cmt( * ) { }
663
- pc_impure {
664
- alt self. req_maps. pure_map. find( scope_id) {
665
- none { }
666
- some( e) { self . is_pure = pc_cmt( e) }
667
- }
668
- }
669
- }
670
- }
671
-
672
685
fn check_for_conflicting_loans( scope_id: ast:: node_id) {
673
686
let new_loanss = alt self . req_maps. req_loan_map. find( scope_id) {
674
687
none { ret; }
@@ -739,10 +752,14 @@ impl methods for check_loan_ctxt {
739
752
// if this is a pure function, only loan-able state can be
740
753
// assigned, because it is uniquely tied to this function and
741
754
// is not visible from the outside
742
- if self . is_pure != pc_impure && cmt. lp. is_none( ) {
743
- self . report_purity_error(
744
- ex. span,
745
- at. ing_form( self . bccx. cmt_to_str( cmt) ) ) ;
755
+ alt self . purity( ex. id) {
756
+ none { }
757
+ some( pc) {
758
+ if cmt. lp. is_none( ) {
759
+ self . report_purity_error(
760
+ pc, ex. span, at. ing_form( self . bccx. cmt_to_str( cmt) ) ) ;
761
+ }
762
+ }
746
763
}
747
764
748
765
// check for a conflicting loan as well, except in the case of
@@ -775,11 +792,8 @@ impl methods for check_loan_ctxt {
775
792
self . bccx. add_to_mutbl_map( cmt) ;
776
793
}
777
794
778
- fn report_purity_error( sp: span, msg: str ) {
779
- alt copy self . is_pure {
780
- pc_impure {
781
- self . tcx( ) . sess. bug( "report_purity_error( ) called when impure") ;
782
- }
795
+ fn report_purity_error( pc: purity_cause, sp: span, msg: str ) {
796
+ alt pc {
783
797
pc_declaration {
784
798
self . tcx( ) . sess. span_err(
785
799
sp,
@@ -855,7 +869,7 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
855
869
visitor: visit:: vt<check_loan_ctxt>) {
856
870
857
871
save_and_restore( self . in_ctor) { ||
858
- save_and_restore( self . is_pure ) { ||
872
+ save_and_restore( self . declared_purity ) { ||
859
873
// In principle, we could consider fk_anon(*) or
860
874
// fk_fn_block(*) to be in a ctor, I suppose, but the
861
875
// purpose of the in_ctor flag is to allow modifications
@@ -870,10 +884,7 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
870
884
// NDM this doesn't seem algother right, what about fn items
871
885
// nested in pure fns? etc?
872
886
873
- alt decl. purity {
874
- ast:: pure_fn { self . is_pure = pc_declaration; }
875
- _ { }
876
- }
887
+ self . declared_purity = decl. purity;
877
888
878
889
visit:: visit_fn( fk, decl, body, sp, id, self , visitor) ;
879
890
}
@@ -884,16 +895,7 @@ fn check_loans_in_expr(expr: @ast::expr,
884
895
& & self : check_loan_ctxt,
885
896
vt: visit:: vt < check_loan_ctxt > ) {
886
897
self . check_for_conflicting_loans( expr. id) ;
887
- save_and_restore( self . is_pure) { ||
888
- self . check_for_purity_requirement( expr. id) ;
889
- check_loans_in_expr_1( expr, self , vt) ;
890
- }
891
- }
892
898
893
- // avoid rightward drift by breaking this out into its own fn
894
- fn check_loans_in_expr_1( expr: @ast:: expr,
895
- & & self : check_loan_ctxt,
896
- vt: visit:: vt < check_loan_ctxt > ) {
897
899
alt expr. node {
898
900
ast : : expr_swap( l, r) {
899
901
self . check_assignment( at_swap, l) ;
@@ -936,9 +938,12 @@ fn check_loans_in_expr_1(expr: @ast::expr,
936
938
}
937
939
}
938
940
ast:: expr_call( f, args, _) {
939
- if self . is_pure != pc_impure {
940
- self. check_pure( f) ;
941
- for args. each { |arg| self . check_pure( arg) }
941
+ alt self. purity( expr. id) {
942
+ none { }
943
+ some( pc) {
944
+ self . check_pure( pc, f) ;
945
+ for args. each { |arg| self . check_pure( pc, arg) }
946
+ }
942
947
}
943
948
let arg_tys = ty:: ty_fn_args( ty:: expr_ty( self . tcx( ) , f) ) ;
944
949
vec:: iter2( args, arg_tys) { |arg, arg_ty|
@@ -963,28 +968,17 @@ fn check_loans_in_expr_1(expr: @ast::expr,
963
968
fn check_loans_in_block( blk: ast:: blk,
964
969
& & self : check_loan_ctxt,
965
970
vt: visit:: vt < check_loan_ctxt > ) {
966
- save_and_restore( self . is_pure ) { ||
971
+ save_and_restore( self . declared_purity ) { ||
967
972
self . check_for_conflicting_loans( blk. node. id) ;
968
- self . check_for_purity_requirement( blk. node. id) ;
969
973
970
974
alt blk. node. rules {
971
975
ast : : default_blk {
972
976
}
973
977
ast:: unchecked_blk {
974
- alt self. is_pure {
975
- pc_impure | pc_declaration {
976
- self. is_pure = pc_impure;
977
- }
978
- pc_cmt( _) {
979
- // unchecked does not override purity requirements due
980
- // to borrows; unchecked didn't seem strong enough to
981
- // justify potential memory unsafety to me
982
- }
983
- }
978
+ self. declared_purity = ast : : impure_fn;
984
979
}
985
980
ast:: unsafe_blk {
986
- // unsafe blocks override everything
987
- self. is_pure = pc_impure;
981
+ self. declared_purity = ast : : unsafe_fn;
988
982
}
989
983
}
990
984
@@ -1472,6 +1466,15 @@ impl categorize_methods for borrowck_ctxt {
1472
1466
ty_to_str( self . tcx, cmt. ty) ]
1473
1467
}
1474
1468
1469
+ fn pk_to_sigil( pk: ptr_kind) -> str {
1470
+ alt pk {
1471
+ uniq_ptr { "~"}
1472
+ gc_ptr { "@"}
1473
+ region_ptr {" & "}
1474
+ unsafe_ptr {" * "}
1475
+ }
1476
+ }
1477
+
1475
1478
fn cmt_to_str( cmt: cmt) -> str {
1476
1479
let mut_str = self . mut_to_str( cmt. mutbl) ;
1477
1480
alt cmt. cat {
@@ -1482,7 +1485,8 @@ impl categorize_methods for borrowck_ctxt {
1482
1485
cat_rvalue { "non-lvalue" }
1483
1486
cat_local( _) { mut_str + " local variable" }
1484
1487
cat_arg( _) { mut_str + " argument" }
1485
- cat_deref( * ) { "dereference of " + mut_str + " pointer" }
1488
+ cat_deref( _, _, pk) { #fmt[ "dereference of %s %s pointer" ,
1489
+ mut_str, self . pk_to_sigil( pk) ] }
1486
1490
cat_stack_upvar( _) { mut_str + " upvar" }
1487
1491
cat_comp( _, comp_field( _) ) { mut_str + " field" }
1488
1492
cat_comp( _, comp_tuple) { "tuple content" }
0 commit comments