3 * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
4 * Copyright (C) 2006, 2007 Ecole des Mines de Nantes
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License (GPL)
8 * version 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * file license.txt for more details.
24 module Lib
= Lib_parsing_c
26 (*****************************************************************************)
28 (*****************************************************************************)
29 let pr2, pr2_once
= Common.mk_pr2_wrappers
Flag_parsing_c.verbose_cfg
31 (*****************************************************************************)
32 (* todo?: compute target level with goto (but rare that different I think)
34 * ver2: compute depth of label (easy, intercept compound in the visitor)
36 * checktodo: after a switch, need check that all the st in the
37 * compound start with a case: ?
39 * checktodo: how ensure that when we call aux_statement recursivly, we
40 * pass it xi_lbl and not just auxinfo ? how enforce that ?
41 * in fact we must either pass a xi_lbl or a newxi
43 * todo: can have code (and so nodes) in many places, in the size of an
44 * array, in the init of initializer, but also in StatementExpr, ...
46 * todo?: steal code from CIL ? (but seems complicated ... again) *)
47 (*****************************************************************************)
49 (*****************************************************************************)
51 (*****************************************************************************)
54 | DeadCode
of Common.parse_info
option
55 | CaseNoSwitch
of Common.parse_info
56 | OnlyBreakInSwitch
of Common.parse_info
57 | WeirdSwitch
of Common.parse_info
58 | NoEnclosingLoop
of Common.parse_info
59 | GotoCantFindLabel
of string * Common.parse_info
60 | NoExit
of Common.parse_info
61 | DuplicatedLabel
of string
64 | Define
of Common.parse_info
66 exception Error
of error
68 (*****************************************************************************)
70 (*****************************************************************************)
72 let add_node node labels nodestr g
=
73 g#
add_node (Control_flow_c.mk_node node labels
[] nodestr
)
74 let add_bc_node node labels parent_labels nodestr g
=
75 g#
add_node (Control_flow_c.mk_node node labels parent_labels nodestr
)
76 let add_arc_opt (starti
, nodei
) g
=
77 starti
+> do_option
(fun starti
-> g#add_arc
((starti
, nodei
), Direct
))
82 let pinfo_of_ii ii
= Ast_c.get_opi
(List.hd ii
).Ast_c.pinfo
86 (*****************************************************************************)
87 (* Contextual information passed in aux_statement *)
88 (*****************************************************************************)
90 (* Sometimes have a continue/break and we must know where we must jump.
92 * ctl_brace: The node list in context_info record the number of '}' at the
93 * context point, for instance at the switch point. So that when deeper,
94 * we can compute the difference between the number of '}' from root to
95 * the context point to close the good number of '}' . For instance
96 * where there is a 'continue', we must close only until the for.
100 | LoopInfo
of nodei
* nodei
(* start, end *) * node list
* int list
101 | SwitchInfo
of nodei
* nodei
(* start, end *) * node list
* int list
103 (* for the Compound case I need to do different things depending if
104 * the compound is the compound of the function definition, the compound of
105 * a switch, so this type allows to specify this and enable to factorize
106 * code for the Compound
108 and compound_caller
=
109 FunctionDef
| Statement
| Switch
of (nodei
-> xinfo
-> xinfo
)
111 (* other information used internally in ast_to_flow and passed recursively *)
114 ctx
: context_info
; (* cf above *)
115 ctx_stack
: context_info list
;
117 (* are we under a ifthen[noelse]. Used for ErrorExit *)
119 compound_caller
: compound_caller
;
121 (* does not change recursively. Some kind of globals. *)
122 labels_assoc
: (string, nodei
) oassoc
;
124 errorexiti
: nodei
option;
126 (* ctl_braces: the nodei list is to handle current imbrication depth.
127 * It contains the must-close '}'.
128 * update: now it is instead a node list.
140 under_ifthen
= false;
141 compound_caller
= Statement
;
145 (* don't change when recurse *)
146 labels_assoc
= new oassocb
[];
152 (*****************************************************************************)
153 (* (Semi) Globals, Julia's style. *)
154 (*****************************************************************************)
156 let g = ref (new ograph_mutable
)
158 let counter_for_labels = ref 0
159 let counter_for_braces = ref 0
161 (* For switch we use compteur too (or pass int ref) cos need know order of the
162 * case if then later want to go from CFG to (original) AST.
163 * update: obsolete now I think
165 let counter_for_switch = ref 0
168 (*****************************************************************************)
170 (*****************************************************************************)
172 (* alt: do via a todo list, so can do all in one pass (but more complex)
173 * todo: can also count the depth level and associate it to the node, for
176 let compute_labels_and_create_them st
=
178 (* map C label to index number in graph *)
179 let (h
: (string, nodei
) oassoc
ref) = ref (new oassocb
[]) in
182 st
+> Visitor_c.vk_statement
{ Visitor_c.default_visitor_c
with
183 Visitor_c.kstatement
= (fun (k
, bigf
) st
->
184 match Ast_c.unwrap_st st
with
185 | Labeled
(Ast_c.Label
(name
, _st
)) ->
186 let ii = Ast_c.get_ii_st_take_care st
in
187 (* at this point I put a lbl_0, but later I will put the
189 let s = Ast_c.str_of_name name
in
190 let newi = !g +> add_node (Label
(st
,name
, ((),ii))) lbl_0 (s^
":")
193 (* the C label already exists ? *)
194 if (!h#haskey
s) then raise
(Error
(DuplicatedLabel
s));
195 h
:= !h#add
(s, newi);
196 (* not k _st !!! otherwise in lbl1: lbl2: i++; we miss lbl2 *)
207 let insert_all_braces xs starti
=
208 xs
+> List.fold_left
(fun acc node
->
209 (* Have to build a new node (clone), cos cant share it.
210 * update: This is now done by the caller. The clones are in xs.
212 let newi = !g#
add_node node
in
213 !g#add_arc
((acc
, newi), Direct
);
217 (*****************************************************************************)
219 (*****************************************************************************)
221 (* Take in a (optional) start node, return an (optional) end node.
225 * ver1: old code was returning an nodei, but goto has no end, so
226 * aux_statement should return nodei option.
228 * ver2: old code was taking a nodei, but should also take nodei
231 * ver3: deadCode detection. What is dead code ? When there is no
232 * starti to start from ? So make starti an option too ? Si on arrive
233 * sur un label: au moment d'un deadCode, on peut verifier les
234 * predecesseurs de ce label, auquel cas si y'en a, ca veut dire
235 * qu'en fait c'est pas du deadCode et que donc on peut se permettre
236 * de partir d'un starti à None. Mais si on a xx; goto far:; near:
237 * yy; zz; far: goto near:. Bon ca doit etre un cas tres tres rare,
238 * mais a cause de notre parcours, on va rejeter ce programme car au
239 * moment d'arriver sur near: on n'a pas encore de predecesseurs pour
240 * ce label. De meme, meme le cas simple ou la derniere instruction
241 * c'est un return, alors ca va generer un DeadCode :(
243 * So make a first pass where dont launch exn at all. Create nodes,
244 * if starti is None then dont add arc. Then make a second pass that
245 * just checks that all nodes (except enter) have predecessors.
246 * So make starti an option too. So type is now
248 * nodei option -> statement -> nodei option.
250 * todo?: if the pb is at a fake node, then try first successos that
253 * ver4: because of special needs of coccinelle, need pass more info, cf
254 * type additionnal_info defined above.
256 * - to complete (break, continue (and enclosing loop), switch (and
257 * associated case, casedefault)) we need to pass additionnal info.
258 * The start/exit when enter in a loop, to know the current 'for'.
260 * - to handle the braces, need again pass additionnal info.
262 * - need pass the labels.
264 * convention: xi for the auxinfo passed recursively
268 let rec (aux_statement
: (nodei
option * xinfo
) -> statement
-> nodei
option) =
269 fun (starti
, xi
) stmt
->
271 if not
!Flag_parsing_c.label_strategy_2
272 then incr
counter_for_labels;
275 if !Flag_parsing_c.label_strategy_2
277 else xi
.labels
@ [!counter_for_labels]
280 (* Normally the new auxinfo to pass recursively to the next aux_statement.
281 * But in some cases we add additionnal stuff in which case we don't use
282 * this 'xi_lbl' but a 'newxi' specially built.
285 if !Flag_parsing_c.label_strategy_2
287 compound_caller
= Statement
;
290 labels
= xi
.labels
@ [ !counter_for_labels ];
291 compound_caller
= Statement
;
294 let ii = Ast_c.get_ii_st_take_care stmt
in
296 (* ------------------------- *)
297 match Ast_c.unwrap_st stmt
with
299 (* coupling: the Switch case copy paste parts of the Compound case *)
300 | Ast_c.Compound statxs
->
302 let (i1
, i2
) = tuple_of_list2
ii in
305 incr
counter_for_braces;
306 let brace = !counter_for_braces in
308 let s1 = "{" ^ i_to_s
brace in
309 let s2 = "}" ^ i_to_s
brace in
311 let lbl = match xi
.compound_caller
with
312 | FunctionDef
-> xi
.labels
(* share label with function header *)
313 | Statement
-> xi
.labels
@ [!counter_for_labels]
314 | Switch _
-> xi
.labels
317 let newi = !g +> add_node (SeqStart
(stmt
, brace, i1
)) lbl s1 in
318 let endnode = mk_node
(SeqEnd
(brace, i2
)) lbl [] s2 in
319 let endnode_dup = mk_fake_node
(SeqEnd
(brace, i2
)) lbl [] s2 in
322 mk_node (SeqEnd (brace, Ast_c.fakeInfo())) lbl [] s2 in
325 let newxi = { xi_lbl with braces
= endnode_dup:: xi_lbl.braces
} in
327 let newxi = match xi
.compound_caller
with
328 | Switch todo_in_compound
->
329 (* note that side effect in todo_in_compound *)
330 todo_in_compound
newi newxi
331 | FunctionDef
| Statement
-> newxi
334 !g +> add_arc_opt (starti
, newi);
335 let finishi = Some
newi in
337 aux_statement_list
finishi (xi
, newxi) statxs
340 +> Common.fmap
(fun finishi ->
341 (* subtil: not always return a Some.
342 * Note that if finishi is None, alors forcement ca veut dire
343 * qu'il y'a eu un return (ou goto), et donc forcement les
344 * braces auront au moins ete crée une fois, et donc flow_to_ast
346 * Sauf si le goto revient en arriere ? mais dans ce cas
347 * ca veut dire que le programme boucle. Pour qu'il boucle pas
348 * il faut forcement au moins un return.
350 let endi = !g#
add_node endnode in
351 if xi
.compound_caller
= Statement
353 (let afteri = !g +> add_node AfterNode
lbl "[after]" in
354 !g#add_arc
((newi, afteri), Direct
);
355 !g#add_arc
((afteri, endi), Direct
));
356 !g#add_arc
((finishi, endi), Direct
);
361 (* ------------------------- *)
362 | Labeled
(Ast_c.Label
(name
, st
)) ->
363 let s = Ast_c.str_of_name name
in
364 let ilabel = xi
.labels_assoc#find
s in
365 let node = mk_node
(unwrap
(!g#nodes#find
ilabel)) lbl [] (s ^
":") in
366 !g#replace_node
(ilabel, node);
367 !g +> add_arc_opt (starti
, ilabel);
368 aux_statement
(Some
ilabel, xi_lbl) st
371 | Jump
(Ast_c.Goto name
) ->
372 let s = Ast_c.str_of_name name
in
373 (* special_cfg_ast: *)
374 let newi = !g +> add_node (Goto
(stmt
, name
, ((),ii))) lbl ("goto "^
s^
":")
376 !g +> add_arc_opt (starti
, newi);
378 if !Flag_parsing_c.no_gotos
383 try xi
.labels_assoc#find
s
385 (* jump vers ErrorExit a la place ?
386 * pourquoi tant de "cant jump" ? pas detecté par gcc ?
388 raise
(Error
(GotoCantFindLabel
(s, pinfo_of_ii ii)))
390 (* !g +> add_arc_opt (starti, ilabel);
391 * todo: special_case: suppose that always goto to toplevel of
392 * function, hence the Common.init
393 * todo?: can perhaps report when a goto is not a classic error_goto ?
394 * that is when it does not jump to the toplevel of the function.
396 let newi = insert_all_braces (Common.list_init xi
.braces
) newi in
397 !g#add_arc
((newi, ilabel), Direct
);
401 | Jump
(Ast_c.GotoComputed e
) ->
402 raise
(Error
(ComputedGoto
))
404 (* ------------------------- *)
405 | Ast_c.ExprStatement opte
->
406 (* flow_to_ast: old: when opte = None, then do not add in CFG. *)
411 (match Ast_c.unwrap_expr e
with
412 | FunCall
(e
, _args
) ->
413 (match Ast_c.unwrap_expr e
with
415 Ast_c.str_of_name namef ^
"(...)"
418 | Assignment
(e1
, SimpleAssign
, e2
) ->
419 (match Ast_c.unwrap_expr e1
with
421 Ast_c.str_of_name namevar ^
" = ... ;"
422 | RecordAccess
(e
, field
) ->
423 (match Ast_c.unwrap_expr e
with
425 let sfield = Ast_c.str_of_name field
in
426 Ast_c.str_of_name namevar ^
"." ^
sfield ^
" = ... ;"
434 let newi = !g +> add_node (ExprStatement
(stmt
, (opte
, ii))) lbl s in
435 !g +> add_arc_opt (starti
, newi);
439 (* ------------------------- *)
440 | Selection
(Ast_c.If
(e
, st1
, st2
)) ->
442 let iist2 = Ast_c.get_ii_st_take_care st2
in
443 (match Ast_c.unwrap_st st2
with
444 | Ast_c.ExprStatement
(None
) when null
iist2 ->
445 (* sometime can have ExprStatement None but it is a if-then-else,
446 * because something like if() xx else ;
447 * so must force to have [] in the ii associated with ExprStatement
450 let (i1
,i2
,i3
, iifakeend
) = tuple_of_list4
ii in
451 let ii = [i1
;i2
;i3
] in
452 (* starti -> newi ---> newfakethen -> ... -> finalthen --> lasti
454 * |-> newfakeelse -> ... -> finalelse -|
455 * update: there is now also a link directly to lasti.
457 * because of CTL, now do different things if we are in a ifthen or
460 let newi = !g +> add_node (IfHeader
(stmt
, (e
, ii))) lbl ("if") in
461 !g +> add_arc_opt (starti
, newi);
462 let newfakethen = !g +> add_node TrueNode
lbl "[then]" in
463 let newfakeelse = !g +> add_node FallThroughNode
lbl "[fallthrough]" in
464 let afteri = !g +> add_node AfterNode
lbl "[after]" in
465 let lasti = !g +> add_node (EndStatement
(Some iifakeend
)) lbl "[endif]"
468 (* for ErrorExit heuristic *)
469 let newxi = { xi_lbl with under_ifthen
= true; } in
471 !g#add_arc
((newi, newfakethen), Direct
);
472 !g#add_arc
((newi, newfakeelse), Direct
);
473 !g#add_arc
((newi, afteri), Direct
);
474 !g#add_arc
((afteri, lasti), Direct
);
475 !g#add_arc
((newfakeelse, lasti), Direct
);
477 let finalthen = aux_statement
(Some
newfakethen, newxi) st1
in
478 !g +> add_arc_opt (finalthen, lasti);
482 (* starti -> newi ---> newfakethen -> ... -> finalthen --> lasti
484 * |-> newfakeelse -> ... -> finalelse -|
485 * update: there is now also a link directly to lasti.
487 let (iiheader
, iielse
, iifakeend
) =
489 | [i1
;i2
;i3
;i4
;i5
] -> [i1
;i2
;i3
], i4
, i5
490 | _
-> raise Impossible
492 let newi = !g +> add_node (IfHeader
(stmt
, (e
, iiheader
))) lbl "if" in
493 !g +> add_arc_opt (starti
, newi);
494 let newfakethen = !g +> add_node TrueNode
lbl "[then]" in
495 let newfakeelse = !g +> add_node FalseNode
lbl "[else]" in
496 let elsenode = !g +> add_node (Else iielse
) lbl "else" in
499 !g#add_arc
((newi, newfakethen), Direct
);
500 !g#add_arc
((newi, newfakeelse), Direct
);
502 !g#add_arc
((newfakeelse, elsenode), Direct
);
504 let finalthen = aux_statement
(Some
newfakethen, xi_lbl) st1
in
505 let finalelse = aux_statement
(Some
elsenode, xi_lbl) st2
in
507 (match finalthen, finalelse with
508 | (None
, None
) -> None
511 !g +> add_node (EndStatement
(Some iifakeend
)) lbl "[endif]" in
513 !g +> add_node AfterNode
lbl "[after]" in
514 !g#add_arc
((newi, afteri), Direct
);
515 !g#add_arc
((afteri, lasti), Direct
);
517 !g +> add_arc_opt (finalthen, lasti);
518 !g +> add_arc_opt (finalelse, lasti);
523 (* ------------------------- *)
524 | Selection
(Ast_c.Switch
(e
, st
)) ->
525 let (i1
,i2
,i3
, iifakeend
) = tuple_of_list4
ii in
526 let ii = [i1
;i2
;i3
] in
528 (* The newswitchi is for the labels to know where to attach.
529 * The newendswitch (endi) is for the 'break'. *)
531 !g+> add_node (SwitchHeader
(stmt
,(e
,ii))) lbl "switch" in
533 !g +> add_node (EndStatement
(Some iifakeend
)) lbl "[endswitch]" in
535 !g +> add_arc_opt (starti
, newswitchi);
537 (* call compound case. Need special info to pass to compound case
538 * because we need to build a context_info that need some of the
539 * information build inside the compound case: the nodei of {
542 match Ast_c.unwrap_st st
with
543 | Ast_c.Compound statxs
->
545 let statxs = Lib.stmt_elems_of_sequencable
statxs in
547 (* todo? we should not allow to match a stmt that corresponds
548 * to a compound of a switch, so really SeqStart (stmt, ...)
549 * here ? so maybe should change the SeqStart labeling too.
550 * So need pass a todo_in_compound2 function.
552 let todo_in_compound newi newxi =
553 let newxi'
= { newxi with
554 ctx
= SwitchInfo
(newi(*!!*), newendswitch, xi
.braces
, lbl);
555 ctx_stack
= newxi.ctx
::newxi.ctx_stack
558 !g#add_arc
((newswitchi, newi), Direct
);
559 (* new: if have not a default case, then must add an edge
560 * between start to end.
561 * todo? except if the case[range] coverthe whole spectrum
563 if not
(statxs +> List.exists
(fun x
->
564 match Ast_c.unwrap_st x
with
565 | Labeled
(Ast_c.Default _
) -> true
569 (* when there is no default, then a valid path is
570 * from the switchheader to the end. In between we
574 let newafter = !g+>add_node FallThroughNode
lbl "[switchfall]"
576 !g#add_arc
((newafter, newendswitch), Direct
);
577 !g#add_arc
((newswitchi, newafter), Direct
);
579 !g#add_arc ((newswitchi, newendswitch), Direct) +> adjust_g;
584 let newxi = { xi_lbl with compound_caller
= (* was xi *)
585 Switch
todo_in_compound
588 aux_statement
(None
(* no starti *), newxi) st
590 (* apparently gcc allows some switch body such as
591 * switch (i) case 0 : printf("here\n");
592 * cf tests-bis/switch_no_body.c
593 * but I don't think it's worthwile to handle
594 * such pathological and rare case. Not worth
595 * the complexity. Safe to assume a coumpound.
597 raise
(Error
(WeirdSwitch
(pinfo_of_ii [i1
])))
599 !g +> add_arc_opt (finalthen, newendswitch);
602 (* what if has only returns inside. We must try to see if the
603 * newendswitch has been used via a 'break;' or because no
607 (match finalthen with
610 let afteri = !g +> add_node AfterNode
lbl "[after]" in
611 !g#add_arc
((newswitchi, afteri), Direct
);
612 !g#add_arc
((afteri, newendswitch), Direct
);
615 !g#add_arc
((finalthen, newendswitch), Direct
);
618 if (!g#predecessors
newendswitch)#null
620 assert ((!g#successors
newendswitch)#null
);
621 !g#del_node
newendswitch;
626 let afteri = !g +> add_node AfterNode
lbl "[after]" in
627 !g#add_arc
((newswitchi, afteri), Direct
);
628 !g#add_arc
((afteri, newendswitch), Direct
);
638 | Labeled
(Ast_c.Case
(_
, _
))
639 | Labeled
(Ast_c.CaseRange
(_
, _
, _
)) ->
641 incr
counter_for_switch;
642 let switchrank = !counter_for_switch in
644 match Ast_c.get_st_and_ii stmt
with
645 | Labeled
(Ast_c.Case
(e
, st
)), ii ->
646 (Case
(stmt
, (e
, ii))), st
647 | Labeled
(Ast_c.CaseRange
(e
, e2
, st
)), ii ->
648 (CaseRange
(stmt
, ((e
, e2
), ii))), st
649 | _
-> raise Impossible
652 let newi = !g +> add_node node lbl "case:" in
654 (match Common.optionise
(fun () ->
656 (xi
.ctx
::xi
.ctx_stack
) +> Common.find_some
(function
657 | SwitchInfo
(a
, b
, c
, _
) -> Some
(a
, b
, c
)
661 | Some
(startbrace
, switchendi
, _braces
) ->
662 (* no need to attach to previous for the first case, cos would be
664 starti
+> do_option
(fun starti
->
665 if starti
<> startbrace
666 then !g +> add_arc_opt (Some starti
, newi);
669 let s = ("[casenode] " ^ i_to_s
switchrank) in
670 let newcasenodei = !g +> add_node (CaseNode
switchrank) lbl s in
671 !g#add_arc
((startbrace
, newcasenodei), Direct
);
672 !g#add_arc
((newcasenodei, newi), Direct
);
673 | None
-> raise
(Error
(CaseNoSwitch
(pinfo_of_ii ii)))
675 aux_statement
(Some
newi, xi_lbl) st
678 | Labeled
(Ast_c.Default st
) ->
679 incr
counter_for_switch;
680 let switchrank = !counter_for_switch in
682 let newi = !g +> add_node (Default
(stmt
, ((),ii))) lbl "case default:" in
683 !g +> add_arc_opt (starti
, newi);
686 | SwitchInfo
(startbrace
, switchendi
, _braces
, _parent_lbl
) ->
687 let s = ("[casenode] " ^ i_to_s
switchrank) in
688 let newcasenodei = !g +> add_node (CaseNode
switchrank) lbl s in
689 !g#add_arc
((startbrace
, newcasenodei), Direct
);
690 !g#add_arc
((newcasenodei, newi), Direct
);
691 | _
-> raise
(Error
(CaseNoSwitch
(pinfo_of_ii ii)))
693 aux_statement
(Some
newi, xi_lbl) st
700 (* ------------------------- *)
701 | Iteration
(Ast_c.While
(e
, st
)) ->
702 (* starti -> newi ---> newfakethen -> ... -> finalthen -
703 * |---|-----------------------------------|
707 let (i1
,i2
,i3
, iifakeend
) = tuple_of_list4
ii in
708 let ii = [i1
;i2
;i3
] in
710 let newi = !g +> add_node (WhileHeader
(stmt
, (e
,ii))) lbl "while" in
711 !g +> add_arc_opt (starti
, newi);
712 let newfakethen = !g +> add_node InLoopNode
lbl "[whiletrue]" in
713 (* let newfakeelse = !g +> add_node FalseNode lbl "[endwhile]" in *)
714 let newafter = !g +> add_node LoopFallThroughNode
lbl "[whilefall]" in
716 !g +> add_node (EndStatement
(Some iifakeend
)) lbl "[endwhile]" in
718 let newxi = { xi_lbl with
719 ctx
= LoopInfo
(newi, newfakeelse, xi_lbl.braces
, lbl);
720 ctx_stack
= xi_lbl.ctx
::xi_lbl.ctx_stack
724 !g#add_arc
((newi, newfakethen), Direct
);
725 !g#add_arc
((newafter, newfakeelse), Direct
);
726 !g#add_arc
((newi, newafter), Direct
);
727 let finalthen = aux_statement
(Some
newfakethen, newxi) st
in
729 (finalthen, if !Flag_parsing_c.no_loops
then newafter else newi);
733 (* This time, may return None, for instance if goto in body of dowhile
734 * (whereas While cant return None). But if return None, certainly
737 | Iteration
(Ast_c.DoWhile
(st
, e
)) ->
738 (* starti -> doi ---> ... ---> finalthen (opt) ---> whiletaili
739 * |--------- newfakethen ---------------| |---> newfakelse
742 match Ast_c.unwrap_expr e
with
743 | Constant
(Int
("0",_
)) -> true
747 let (iido
, iiwhiletail
, iifakeend
) =
749 | [i1
;i2
;i3
;i4
;i5
;i6
] -> i1
, [i2
;i3
;i4
;i5
], i6
750 | _
-> raise Impossible
752 let doi = !g +> add_node (DoHeader
(stmt
, iido
)) lbl "do" in
753 !g +> add_arc_opt (starti
, doi);
754 let taili = !g +> add_node (DoWhileTail
(e
, iiwhiletail
)) lbl "whiletail"
758 (*let newfakeelse = !g +> add_node FalseNode lbl "[enddowhile]" in *)
759 let newafter = !g +> add_node FallThroughNode
lbl "[dowhilefall]" in
761 !g +> add_node (EndStatement
(Some iifakeend
)) lbl "[enddowhile]" in
763 let afteri = !g +> add_node AfterNode
lbl "[after]" in
764 !g#add_arc
((doi,afteri), Direct
);
765 !g#add_arc
((afteri,newfakeelse), Direct
);
767 let newxi = { xi_lbl with
768 ctx
= LoopInfo
(taili, newfakeelse, xi_lbl.braces
, lbl);
769 ctx_stack
= xi_lbl.ctx
::xi_lbl.ctx_stack
773 if not
is_zero && (not
!Flag_parsing_c.no_loops
)
775 let newfakethen = !g +> add_node InLoopNode
lbl "[dowhiletrue]" in
776 !g#add_arc
((taili, newfakethen), Direct
);
777 !g#add_arc
((newfakethen, doi), Direct
);
780 !g#add_arc
((newafter, newfakeelse), Direct
);
781 !g#add_arc
((taili, newafter), Direct
);
784 let finalthen = aux_statement
(Some
doi, newxi) st
in
785 (match finalthen with
787 if (!g#predecessors
taili)#null
788 then raise
(Error
(DeadCode
(Some
(pinfo_of_ii ii))))
789 else Some
newfakeelse
791 !g#add_arc
((finali
, taili), Direct
);
797 | Iteration
(Ast_c.For
(e1opt
, e2opt
, e3opt
, st
)) ->
798 let (i1
,i2
,i3
, iifakeend
) = tuple_of_list4
ii in
799 let ii = [i1
;i2
;i3
] in
802 !g+>add_node(ForHeader
(stmt
,((e1opt
,e2opt
,e3opt
),ii))) lbl "for" in
803 !g +> add_arc_opt (starti
, newi);
804 let newfakethen = !g +> add_node InLoopNode
lbl "[fortrue]" in
805 (*let newfakeelse = !g +> add_node FalseNode lbl "[endfor]" in*)
806 let newafter = !g +> add_node LoopFallThroughNode
lbl "[forfall]" in
808 !g +> add_node (EndStatement
(Some iifakeend
)) lbl "[endfor]" in
810 let newxi = { xi_lbl with
811 ctx
= LoopInfo
(newi, newfakeelse, xi_lbl.braces
, lbl);
812 ctx_stack
= xi_lbl.ctx
::xi_lbl.ctx_stack
816 !g#add_arc
((newi, newfakethen), Direct
);
817 !g#add_arc
((newafter, newfakeelse), Direct
);
818 !g#add_arc
((newi, newafter), Direct
);
819 let finalthen = aux_statement
(Some
newfakethen, newxi) st
in
822 if !Flag_parsing_c.no_loops
then newafter else newi);
826 (* to generate less exception with the breakInsideLoop, analyse
827 * correctly the loop deguisé comme list_for_each. Add a case ForMacro
828 * in ast_c (and in lexer/parser), and then do code that imitates the
830 * update: the list_for_each was previously converted into Tif by the
831 * lexer, now they are returned as Twhile so less pbs. But not perfect.
832 * update: now I recognize the list_for_each macro so no more problems.
834 | Iteration
(Ast_c.MacroIteration
(s, es
, st
)) ->
835 let (i1
,i2
,i3
, iifakeend
) = tuple_of_list4
ii in
836 let ii = [i1
;i2
;i3
] in
839 !g+>add_node(MacroIterHeader
(stmt
,((s,es
),ii))) lbl "foreach" in
840 !g +> add_arc_opt (starti
, newi);
841 let newfakethen = !g +> add_node InLoopNode
lbl "[fortrue]" in
842 (*let newfakeelse = !g +> add_node FalseNode lbl "[endfor]" in*)
843 let newafter = !g +> add_node LoopFallThroughNode
lbl "[foreachfall]" in
845 !g +> add_node (EndStatement
(Some iifakeend
)) lbl "[endforeach]" in
847 let newxi = { xi_lbl with
848 ctx
= LoopInfo
(newi, newfakeelse, xi_lbl.braces
, lbl);
849 ctx_stack
= xi_lbl.ctx
::xi_lbl.ctx_stack
853 !g#add_arc
((newi, newfakethen), Direct
);
854 !g#add_arc
((newafter, newfakeelse), Direct
);
855 !g#add_arc
((newi, newafter), Direct
);
856 let finalthen = aux_statement
(Some
newfakethen, newxi) st
in
859 if !Flag_parsing_c.no_loops
then newafter else newi);
864 (* ------------------------- *)
865 | Jump
((Ast_c.Continue
|Ast_c.Break
) as x
) ->
868 SwitchInfo
(startbrace
, loopendi
, braces
, parent_lbl
) ->
873 xi
.ctx_stack
+> Common.find_some
(function
874 LoopInfo
(_
,_
,_
,_
) as c
-> Some c
877 raise
(Error
(OnlyBreakInSwitch
(pinfo_of_ii ii))))
878 | LoopInfo
(loopstarti
, loopendi
, braces
, parent_lbl
) -> xi
.ctx
879 | NoInfo
-> raise
(Error
(NoEnclosingLoop
(pinfo_of_ii ii))) in
882 match context_info with
883 LoopInfo
(loopstarti
, loopendi
, braces
, parent_lbl
) -> parent_lbl
884 | SwitchInfo
(startbrace
, loopendi
, braces
, parent_lbl
) -> parent_lbl
885 | NoInfo
-> raise Impossible
in
888 let (node_info
, string) =
890 String.concat
"," (List.map string_of_int
parent_label) in
893 (Continue
(stmt
, ((), ii)),
894 Printf.sprintf
"continue; [%s]" parent_string)
896 (Break
(stmt
, ((), ii)),
897 Printf.sprintf
"break; [%s]" parent_string)
898 | _
-> raise Impossible
901 (* idea: break or continue records the label of its parent loop or
903 let newi = !g +> add_bc_node node_info
lbl parent_label string in
904 !g +> add_arc_opt (starti
, newi);
906 (* let newi = some starti in *)
908 (match context_info with
909 | LoopInfo
(loopstarti
, loopendi
, braces
, parent_lbl
) ->
912 | Ast_c.Break
-> loopendi
914 (* if no loops, then continue behaves like break - just
916 if !Flag_parsing_c.no_loops
then loopendi
else loopstarti
917 | x
-> raise Impossible
919 let difference = List.length xi
.braces
- List.length braces
in
920 assert (difference >= 0);
921 let toend = take
difference xi
.braces
in
922 let newi = insert_all_braces toend newi in
923 !g#add_arc
((newi, desti), Direct
);
926 | SwitchInfo
(startbrace
, loopendi
, braces
, parent_lbl
) ->
927 assert (x
=*= Ast_c.Break
);
928 let difference = List.length xi
.braces
- List.length braces
in
929 assert (difference >= 0);
930 let toend = take
difference xi
.braces
in
931 let newi = insert_all_braces toend newi in
932 !g#add_arc
((newi, loopendi
), Direct
);
934 | NoInfo
-> raise Impossible
937 | Jump
((Ast_c.Return
| Ast_c.ReturnExpr _
) as kind
) ->
938 (match xi
.exiti
, xi
.errorexiti
with
939 | None
, None
-> raise
(Error
(NoExit
(pinfo_of_ii ii)))
940 | Some exiti
, Some errorexiti
->
945 | Ast_c.Return
-> "return"
946 | Ast_c.ReturnExpr _
-> "return ..."
947 | _
-> raise Impossible
952 | Ast_c.Return
-> Return
(stmt
, ((),ii))
953 | Ast_c.ReturnExpr e
-> ReturnExpr
(stmt
, (e
, ii))
954 | _
-> raise Impossible
958 !g +> add_arc_opt (starti
, newi);
959 let newi = insert_all_braces xi
.braces
newi in
962 then !g#add_arc
((newi, errorexiti
), Direct
)
963 else !g#add_arc
((newi, exiti
), Direct
)
966 | _
-> raise Impossible
970 (* ------------------------- *)
975 ([{v_namei
= Some
(name
, _
); v_type
= typ
; v_storage
= sto
}, _
], _
)) ->
976 "decl:" ^
Ast_c.str_of_name name
977 | _
-> "decl_novar_or_multivar"
980 let newi = !g +> add_node (Decl
(decl
)) lbl s in
981 !g +> add_arc_opt (starti
, newi);
984 (* ------------------------- *)
986 let newi = !g +> add_node (Asm
(stmt
, ((body
,ii)))) lbl "asm;" in
987 !g +> add_arc_opt (starti
, newi);
991 let newi = !g +> add_node (MacroStmt
(stmt
, ((),ii))) lbl "macro;" in
992 !g +> add_arc_opt (starti
, newi);
996 (* ------------------------- *)
997 | Ast_c.NestedFunc def
->
998 raise
(Error NestedFunc
)
1006 and aux_statement_list starti
(xi
, newxi) statxs =
1008 +> List.fold_left
(fun starti statement_seq
->
1009 if !Flag_parsing_c.label_strategy_2
1010 then incr
counter_for_labels;
1013 if !Flag_parsing_c.label_strategy_2
1014 then { newxi with labels
= xi
.labels
@ [ !counter_for_labels ] }
1018 match statement_seq
with
1019 | Ast_c.StmtElem statement
->
1020 aux_statement
(starti
, newxi'
) statement
1022 | Ast_c.CppDirectiveStmt directive
->
1023 pr2_once
("ast_to_flow: filter a directive");
1026 | Ast_c.IfdefStmt ifdef
->
1027 pr2_once
("ast_to_flow: filter a directive");
1030 | Ast_c.IfdefStmt2
(ifdefs
, xxs
) ->
1032 let (head
, body
, tail
) = Common.head_middle_tail ifdefs
in
1034 let newi = !g +> add_node (IfdefHeader
(head
)) newxi'
.labels
"[ifdef]" in
1035 let taili = !g +> add_node (IfdefEndif
(tail
)) newxi'
.labels
"[endif]" in
1036 !g +> add_arc_opt (starti
, newi);
1039 body
+> List.map
(fun elseif
->
1041 !g +> add_node (IfdefElse
(elseif
)) newxi'
.labels
"[elseif]" in
1042 !g#add_arc
((newi, elsei), Direct
);
1047 Common.zip
(newi::elsenodes) xxs
+> List.map
(fun (start_nodei
, xs
)->
1049 aux_statement_list
(Some start_nodei
) (newxi, newxi) xs
in
1050 !g +> add_arc_opt (finalthen, taili);
1055 This is an attempt to let a statement metavariable match this
1056 construct, but it doesn't work because #ifdef is not a statement.
1057 Not sure if this is a good or bad thing, at least if there is no else
1058 because then no statement might be there.
1059 let afteri = !g +> add_node AfterNode newxi'.labels "[after]" in
1060 !g#add_arc ((newi, afteri), Direct);
1061 !g#add_arc ((afteri, taili), Direct);
1069 (*****************************************************************************)
1070 (* Definition of function *)
1071 (*****************************************************************************)
1073 let (aux_definition
: nodei
-> definition
-> unit) = fun topi funcdef
->
1075 let lbl_start = [!counter_for_labels] in
1077 let ({f_name
= namefuncs
;
1082 f_old_c_style
= oldstyle
;
1084 let iifunheader, iicompound
=
1086 | ioparen
::icparen
::iobrace
::icbrace
::iifake
::isto
->
1087 ioparen
::icparen
::iifake
::isto
,
1089 | _
-> raise Impossible
1093 let topstatement = Ast_c.mk_st
(Ast_c.Compound compound
) iicompound
in
1095 let headi = !g +> add_node
1097 Ast_c.f_name
= namefuncs
;
1101 f_body
= [] (* empty body *);
1102 f_old_c_style
= oldstyle
;
1104 lbl_start ("function " ^
Ast_c.str_of_name namefuncs
) in
1105 let enteri = !g +> add_node Enter
lbl_0 "[enter]" in
1106 let exiti = !g +> add_node Exit
lbl_0 "[exit]" in
1107 let errorexiti = !g +> add_node ErrorExit
lbl_0 "[errorexit]" in
1109 !g#add_arc
((topi
, headi), Direct
);
1110 !g#add_arc
((headi, enteri), Direct
);
1112 (* ---------------------------------------------------------------- *)
1113 (* todocheck: assert ? such as we have "consommer" tous les labels *)
1117 labels_assoc
= compute_labels_and_create_them topstatement;
1119 errorexiti = Some
errorexiti;
1120 compound_caller
= FunctionDef
;
1124 let lasti = aux_statement
(Some
enteri, info) topstatement in
1125 !g +> add_arc_opt (lasti, exiti)
1127 (*****************************************************************************)
1129 (*****************************************************************************)
1131 (* Helpers for SpecialDeclMacro.
1133 * could also force the coccier to define
1134 * the toplevel macro statement as in @@ toplevel_declarator MACRO_PARAM;@@
1135 * and so I would not need this hack and instead I would to a cleaner
1136 * match in cocci_vs_c_3.ml of a A.MacroTop vs B.MacroTop
1138 * todo: update: now I do what I just described, so can remove this code ?
1140 let specialdeclmacro_to_stmt (s, args
, ii) =
1141 let (iis
, iiopar
, iicpar
, iiptvirg
) = tuple_of_list4
ii in
1142 let ident = Ast_c.RegularName
(s, [iis
]) in
1143 let identfinal = Ast_c.mk_e
(Ast_c.Ident
(ident)) Ast_c.noii
in
1144 let f = Ast_c.mk_e
(Ast_c.FunCall
(identfinal, args
)) [iiopar
;iicpar
] in
1145 let stmt = Ast_c.mk_st
(Ast_c.ExprStatement
(Some
f)) [iiptvirg
] in
1146 stmt, (f, [iiptvirg
])
1150 let ast_to_control_flow e
=
1152 (* globals (re)initialialisation *)
1153 g := (new ograph_mutable
);
1154 counter_for_labels := 1;
1155 counter_for_braces := 0;
1156 counter_for_switch := 0;
1158 let topi = !g +> add_node TopNode
lbl_0 "[top]" in
1161 | Ast_c.Definition
((defbis
,_
) as def
) ->
1162 let _funcs = defbis
.f_name
in
1163 let _c = defbis
.f_body
in
1164 (* if !Flag.show_misc then pr2 ("build info function " ^ funcs); *)
1165 aux_definition
topi def
;
1168 | Ast_c.Declaration _
1169 | Ast_c.CppTop
(Ast_c.Include _
)
1174 | Ast_c.Declaration decl
->
1175 (Control_flow_c.Decl decl
), "decl"
1176 | Ast_c.CppTop
(Ast_c.Include inc
) ->
1177 (Control_flow_c.Include inc
), "#include"
1178 | Ast_c.MacroTop
(s, args
, ii) ->
1179 let (st
, (e
, ii)) = specialdeclmacro_to_stmt (s, args
, ii) in
1180 (Control_flow_c.ExprStatement
(st
, (Some e
, ii))), "macrotoplevel"
1181 (*(Control_flow_c.MacroTop (s, args,ii), "macrotoplevel") *)
1182 | _
-> raise Impossible
1184 let ei = !g +> add_node elem
lbl_0 str
in
1185 let endi = !g +> add_node EndNode
lbl_0 "[end]" in
1187 !g#add_arc
((topi, ei),Direct
);
1188 !g#add_arc
((ei, endi),Direct
);
1191 | Ast_c.CppTop
(Ast_c.Define
((id
,ii), (defkind
, defval
))) ->
1194 Ast_c.Undef
-> "#undef " ^ id
1195 | _
-> "#define " ^ id
in
1196 let headeri = !g+>add_node (DefineHeader
((id
, ii), defkind
)) lbl_0 s in
1197 !g#add_arc
((topi, headeri),Direct
);
1200 | Ast_c.DefineExpr e
->
1201 let ei = !g +> add_node (DefineExpr e
) lbl_0 "defexpr" in
1202 let endi = !g +> add_node EndNode
lbl_0 "[end]" in
1203 !g#add_arc
((headeri, ei) ,Direct
);
1204 !g#add_arc
((ei, endi) ,Direct
);
1206 | Ast_c.DefineType ft
->
1207 let ei = !g +> add_node (DefineType ft
) lbl_0 "deftyp" in
1208 let endi = !g +> add_node EndNode
lbl_0 "[end]" in
1209 !g#add_arc
((headeri, ei) ,Direct
);
1210 !g#add_arc
((ei, endi) ,Direct
);
1212 | Ast_c.DefineStmt st
->
1213 (* can have some return; inside the statement *)
1214 let exiti = !g +> add_node Exit
lbl_0 "[exit]" in
1215 let errorexiti = !g +> add_node ErrorExit
lbl_0 "[errorexit]" in
1216 let goto_labels = compute_labels_and_create_them st
in
1218 let info = { initial_info with
1219 labels_assoc
= goto_labels;
1221 errorexiti = Some
errorexiti;
1225 let lasti = aux_statement
(Some
headeri , info) st
in
1226 lasti +> do_option
(fun lasti ->
1227 (* todo? if don't have a lasti ? no EndNode ? CTL will work ? *)
1228 let endi = !g +> add_node EndNode
lbl_0 "[end]" in
1229 !g#add_arc
((lasti, endi), Direct
)
1233 | Ast_c.DefineDoWhileZero
((st
,_e
), ii) ->
1234 let goto_labels = compute_labels_and_create_them st
in
1235 let info = { initial_info with
1236 labels_assoc
= goto_labels } in
1239 !g +> add_node (DefineDoWhileZeroHeader
((),ii)) lbl_0 "do0" in
1240 !g#add_arc
((headeri, headerdoi), Direct
);
1241 let lasti = aux_statement
(Some
headerdoi , info) st
in
1242 lasti +> do_option
(fun lasti ->
1243 let endi = !g +> add_node EndNode
lbl_0 "[end]" in
1244 !g#add_arc
((lasti, endi), Direct
)
1247 | Ast_c.DefineFunction def
->
1248 aux_definition
headeri def
;
1250 | Ast_c.DefineText
(s, s_ii
) ->
1251 raise
(Error
(Define
(pinfo_of_ii ii)))
1252 | Ast_c.DefineEmpty
->
1253 let endi = !g +> add_node EndNode
lbl_0 "[end]" in
1254 !g#add_arc
((headeri, endi),Direct
);
1255 | Ast_c.DefineInit _
->
1256 raise
(Error
(Define
(pinfo_of_ii ii)))
1257 | Ast_c.DefineTodo
->
1258 raise
(Error
(Define
(pinfo_of_ii ii)))
1261 | Ast_c.DefineText (s, ii) ->
1262 let endi = !g +> add_node EndNode lbl_0 "[end]" in
1263 !g#add_arc ((headeri, endi),Direct);
1264 | Ast_c.DefineInit _ ->
1265 let endi = !g +> add_node EndNode lbl_0 "[end]" in
1266 !g#add_arc ((headeri, endi),Direct);
1267 | Ast_c.DefineTodo ->
1268 let endi = !g +> add_node EndNode lbl_0 "[end]" in
1269 !g#add_arc ((headeri, endi),Direct);
1279 (*****************************************************************************)
1280 (* CFG loop annotation *)
1281 (*****************************************************************************)
1283 let annotate_loop_nodes g =
1284 let firsti = Control_flow_c.first_node
g in
1286 (* just for opti a little *)
1287 let already = Hashtbl.create
101 in
1289 g +> Ograph_extended.dfs_iter_with_path
firsti (fun xi path
->
1290 Hashtbl.add
already xi
true;
1291 let succ = g#successors xi
in
1292 let succ = succ#tolist
in
1293 succ +> List.iter
(fun (yi
,_edge
) ->
1294 if Hashtbl.mem
already yi
&& List.mem yi
(xi
::path
)
1296 let node = g#nodes#find yi
in
1297 let ((node2
, nodeinfo
), nodestr
) = node in
1298 let node'
= ((node2
, {nodeinfo
with is_loop
= true}), (nodestr ^
"*"))
1299 in g#replace_node
(yi
, node'
);
1307 (*****************************************************************************)
1309 (*****************************************************************************)
1311 (* the second phase, deadcode detection. Old code was raising DeadCode if
1312 * lasti = None, but maybe not. In fact if have 2 return in the then
1313 * and else of an if ?
1315 * alt: but can assert that at least there exist
1316 * a node to exiti, just check #pred of exiti.
1318 * Why so many deadcode in Linux ? Ptet que le label est utilisé
1319 * mais dans le corps d'une macro et donc on le voit pas :(
1322 let deadcode_detection g =
1324 g#nodes#iter
(fun (k
, node) ->
1325 let pred = g#predecessors k
in
1327 (match unwrap
node with
1330 * | EndStatement _ -> pr2 "deadcode sur fake node, pas grave";
1335 | Exit
-> () (* if have 'loop: if(x) return; i++; goto loop' *)
1336 | SeqEnd _
-> () (* todo?: certaines '}' deviennent orphelins *)
1338 (match Control_flow_c.extract_fullstatement
node with
1340 let ii = Ast_c.get_ii_st_take_care st
in
1341 raise
(Error
(DeadCode
(Some
(pinfo_of_ii ii))))
1342 | _
-> pr2 "CFG: orphelin nodes, maybe something weird happened"
1347 (*------------------------------------------------------------------------*)
1348 (* special_cfg_braces: the check are really specific to the way we
1349 * have build our control_flow, with the { } in the graph so normally
1350 * all those checks here are useless.
1352 * ver1: to better error reporting, to report earlier the message, pass
1353 * the list of '{' (containing morover a brace_identifier) instead of
1357 let (check_control_flow
: cflow
-> unit) = fun g ->
1359 let nodes = g#
nodes in
1360 let starti = first_node
g in
1361 let visited = ref (new oassocb
[]) in
1363 let print_trace_error xs
= pr2 "PB with flow:"; Common.pr2_gen xs
; in
1365 let rec dfs (nodei
, (* Depth depth,*) startbraces
, trace
) =
1366 let trace2 = nodei
::trace
in
1367 if !visited#haskey nodei
1369 (* if loop back, just check that go back to a state where have same depth
1371 let (*(Depth depth2)*) startbraces2
= !visited#find nodei
in
1372 if (*(depth = depth2)*) startbraces
<> startbraces2
1375 pr2 (sprintf
"PB with flow: the node %d has not same braces count"
1377 print_trace_error trace2
1380 let children = g#successors nodei
in
1381 let _ = visited := !visited#add
(nodei
, (* Depth depth*) startbraces
) in
1383 (* old: good, but detect a missing } too late, only at the end
1385 (match fst (nodes#find nodei) with
1386 | StartBrace i -> Depth (depth + 1)
1387 | EndBrace i -> Depth (depth - 1)
1393 (match unwrap
(nodes#find nodei
), startbraces
with
1394 | SeqStart
(_,i
,_), xs
-> i
::xs
1395 | SeqEnd
(i
,_), j
::xs
->
1400 pr2 (sprintf
("PB with flow: not corresponding match between }%d and excpeted }%d at node %d") i j nodei
);
1401 print_trace_error trace2;
1404 | SeqEnd
(i
,_), [] ->
1405 pr2 (sprintf
"PB with flow: too much } at }%d " i
);
1406 print_trace_error trace2;
1413 if null
children#tolist
1415 if (* (depth = 0) *) startbraces
<> []
1416 then print_trace_error trace2
1418 children#tolist
+> List.iter
(fun (nodei
,_) ->
1419 dfs (nodei
, newdepth, trace2)
1423 dfs (starti, (* Depth 0*) [], [])
1425 (*****************************************************************************)
1427 (*****************************************************************************)
1429 let report_error error
=
1430 let error_from_info info =
1431 Common.error_message_short
info.file
("", info.charpos
)
1434 | DeadCode infoopt
->
1436 | None
-> pr2 "FLOW: deadcode detected, but cant trace back the place"
1437 | Some
info -> pr2 ("FLOW: deadcode detected: " ^
error_from_info info)
1439 | CaseNoSwitch
info ->
1440 pr2 ("FLOW: case without corresponding switch: " ^
error_from_info info)
1441 | OnlyBreakInSwitch
info ->
1442 pr2 ("FLOW: only break are allowed in switch: " ^
error_from_info info)
1443 | WeirdSwitch
info ->
1444 pr2 ("FLOW: weird switch: " ^
error_from_info info)
1445 | NoEnclosingLoop
(info) ->
1446 pr2 ("FLOW: can't find enclosing loop: " ^
error_from_info info)
1447 | GotoCantFindLabel
(s, info) ->
1448 pr2 ("FLOW: cant jump to " ^
s ^
": because we can't find this label")
1450 pr2 ("FLOW: can't find exit or error exit: " ^
error_from_info info)
1451 | DuplicatedLabel
s ->
1452 pr2 ("FLOW: duplicate label " ^
s)
1454 pr2 ("FLOW: not handling yet nested function")
1456 pr2 ("FLOW: not handling computed goto yet")
1458 pr2 ("Unsupported form of #define: " ^
error_from_info info)