@@ -1024,6 +1024,75 @@ let populate_tag_graph_node (cx:Semant.ctxt) (id:Common.opaque_id) (n:int) =
1024
1024
in
1025
1025
Array. iter add_ty ty_tup
1026
1026
1027
+ let stack_contains (stack :'a Stack.t ) (elem :'a ) : bool =
1028
+ try
1029
+ Stack. iter (fun elem' -> if elem = elem' then raise Exit ) stack; false
1030
+ with Exit -> true
1031
+
1032
+ let report_infinitely_sized_tag
1033
+ (id :Common.opaque_id )
1034
+ (stack :Common.opaque_id Stack.t )
1035
+ : unit =
1036
+ let string_of_tag_id tag_id =
1037
+ let ty = Ast. TY_tag { Ast. tag_id = tag_id; Ast. tag_args = [| |] } in
1038
+ Ast. sprintf_ty () ty
1039
+ in
1040
+ let msg = Buffer. create 0 in
1041
+ Buffer. add_string msg " found tag of infinite size: " ;
1042
+ while not (Stack. is_empty stack) do
1043
+ Buffer. add_string msg (string_of_tag_id (Stack. pop stack));
1044
+ Buffer. add_string msg " <- "
1045
+ done ;
1046
+ Buffer. add_string msg (string_of_tag_id id);
1047
+ Buffer. add_string msg " ; use '@' for recursive references" ;
1048
+ Common. err None " %s" (Buffer. contents msg)
1049
+
1050
+ let check_for_tag_cycles (cx :Semant.ctxt ) =
1051
+ (* Find cycles in tags using Tarjan's strongly connected components
1052
+ * algorithm. *)
1053
+ let lowlinks = Hashtbl. create 0 in
1054
+ let next_index, stack = ref 0 , Stack. create () in
1055
+
1056
+ let rec check_node id node =
1057
+ if node.Semant. tgn_index = None then begin
1058
+ let index = ! next_index in
1059
+ incr next_index;
1060
+ node.Semant. tgn_index < - Some index;
1061
+
1062
+ Stack. push id stack;
1063
+
1064
+ Hashtbl. add lowlinks id max_int;
1065
+
1066
+ let check_outgoing_edge id' =
1067
+ let node' = Hashtbl. find cx.Semant. ctxt_tag_containment id' in
1068
+ if node'.Semant. tgn_index = None then begin
1069
+ check_node id' node';
1070
+ let lowlink = Hashtbl. find lowlinks id in
1071
+ let lowlink' = Hashtbl. find lowlinks id' in
1072
+ Hashtbl. replace lowlinks id (min lowlink lowlink')
1073
+ end else if stack_contains stack id' then
1074
+ let lowlink = Hashtbl. find lowlinks id in
1075
+ let index' =
1076
+ match node'.Semant. tgn_index with
1077
+ Some index' -> index'
1078
+ | None ->
1079
+ Common. bug
1080
+ ()
1081
+ " check_for_tag_cycles: node in stack without index"
1082
+ in
1083
+ Hashtbl. replace lowlinks id (min lowlink index')
1084
+ in
1085
+
1086
+ Queue. iter check_outgoing_edge node.Semant. tgn_children;
1087
+
1088
+ if index == Hashtbl. find lowlinks id then
1089
+ report_infinitely_sized_tag id stack;
1090
+
1091
+ ignore (Stack. pop stack)
1092
+ end
1093
+ in
1094
+ Hashtbl. iter check_node cx.Semant. ctxt_tag_containment
1095
+
1027
1096
let process_crate (cx :Semant.ctxt ) (crate :Ast.crate ) : unit =
1028
1097
let path = Stack. create () in
1029
1098
let fn_ctx_stack = Stack. create () in
@@ -1139,7 +1208,10 @@ let process_crate (cx:Semant.ctxt) (crate:Ast.crate) : unit =
1139
1208
if not (Hashtbl. mem cx.Semant. ctxt_auto_deref_lval lval_id) then
1140
1209
Hashtbl. add cx.Semant. ctxt_auto_deref_lval lval_id false
1141
1210
in
1142
- Hashtbl. iter fill cx.Semant. ctxt_all_lvals
1211
+ Hashtbl. iter fill cx.Semant. ctxt_all_lvals;
1212
+
1213
+ (* Check for tag cycles. *)
1214
+ check_for_tag_cycles cx
1143
1215
in
1144
1216
1145
1217
{
0 commit comments