~ubuntu-branches/debian/sid/frama-c/sid

« back to all changes in this revision

Viewing changes to cil/src/ext/canonicalize.ml

  • Committer: Bazaar Package Importer
  • Author(s): Mehdi Dogguy
  • Date: 2009-06-03 08:19:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090603081925-kihvxvt0wy3zc4ar
Tags: upstream-20081201.dfsg
ImportĀ upstreamĀ versionĀ 20081201.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(**************************************************************************)
 
2
(*                                                                        *)
 
3
(*  Copyright (C) 2001-2003,                                              *)
 
4
(*   George C. Necula    <necula@cs.berkeley.edu>                         *)
 
5
(*   Scott McPeak        <smcpeak@cs.berkeley.edu>                        *)
 
6
(*   Wes Weimer          <weimer@cs.berkeley.edu>                         *)
 
7
(*   Ben Liblit          <liblit@cs.berkeley.edu>                         *)
 
8
(*  All rights reserved.                                                  *)
 
9
(*                                                                        *)
 
10
(*  Redistribution and use in source and binary forms, with or without    *)
 
11
(*  modification, are permitted provided that the following conditions    *)
 
12
(*  are met:                                                              *)
 
13
(*                                                                        *)
 
14
(*  1. Redistributions of source code must retain the above copyright     *)
 
15
(*  notice, this list of conditions and the following disclaimer.         *)
 
16
(*                                                                        *)
 
17
(*  2. Redistributions in binary form must reproduce the above copyright  *)
 
18
(*  notice, this list of conditions and the following disclaimer in the   *)
 
19
(*  documentation and/or other materials provided with the distribution.  *)
 
20
(*                                                                        *)
 
21
(*  3. The names of the contributors may not be used to endorse or        *)
 
22
(*  promote products derived from this software without specific prior    *)
 
23
(*  written permission.                                                   *)
 
24
(*                                                                        *)
 
25
(*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   *)
 
26
(*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     *)
 
27
(*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS     *)
 
28
(*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE        *)
 
29
(*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,   *)
 
30
(*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  *)
 
31
(*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      *)
 
32
(*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER      *)
 
33
(*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT    *)
 
34
(*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN     *)
 
35
(*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *)
 
36
(*  POSSIBILITY OF SUCH DAMAGE.                                           *)
 
37
(*                                                                        *)
 
38
(*  File modified by CEA (Commissariat ļæ½ l'ļæ½nergie Atomique).             *)
 
39
(**************************************************************************)
 
40
 
 
41
(*
 
42
 *
 
43
 * Copyright (c) 2001-2002,
 
44
 *  George C. Necula    <necula@cs.berkeley.edu>
 
45
 *  Scott McPeak        <smcpeak@cs.berkeley.edu>
 
46
 *  Wes Weimer          <weimer@cs.berkeley.edu>
 
47
 * All rights reserved.
 
48
 *
 
49
 * Redistribution and use in source and binary forms, with or without
 
50
 * modification, are permitted provided that the following conditions are
 
51
 * met:
 
52
 *
 
53
 * 1. Redistributions of source code must retain the above copyright
 
54
 * notice, this list of conditions and the following disclaimer.
 
55
 *
 
56
 * 2. Redistributions in binary form must reproduce the above copyright
 
57
 * notice, this list of conditions and the following disclaimer in the
 
58
 * documentation and/or other materials provided with the distribution.
 
59
 *
 
60
 * 3. The names of the contributors may not be used to endorse or promote
 
61
 * products derived from this software without specific prior written
 
62
 * permission.
 
63
 *
 
64
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 
65
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 
66
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 
67
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 
68
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
69
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
70
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
71
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
72
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
73
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
74
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
75
 *
 
76
 *)
 
77
 
 
78
 
 
79
 
 
80
(************************************************************************
 
81
 * canonicalize performs several transformations to correct differences
 
82
 * between C and C++, so that the output is (hopefully) valid C++ code.
 
83
 * This is incomplete -- certain fixes which are necessary
 
84
 * for some programs are not yet implemented.
 
85
 *
 
86
 * #1) C allows global variables to have multiple declarations and multiple
 
87
 *     (equivalent) definitions. This transformation removes all but one
 
88
 *     declaration and all but one definition.
 
89
 *
 
90
 * #2) Any variables that use C++ keywords as identifiers are renamed.
 
91
 *
 
92
 * #3) __inline is #defined to inline, and __restrict is #defined to nothing.
 
93
 *
 
94
 * #4) C allows function pointers with no specified arguments to be used on
 
95
 *     any argument list.  To make C++ accept this code, we insert a cast
 
96
 *     from the function pointer to a type that matches the arguments.  Of
 
97
 *     course, this does nothing to guarantee that the pointer actually has
 
98
 *     that type.
 
99
 *
 
100
 * #5) Makes casts from int to enum types explicit.  (CIL changes enum
 
101
 *     constants to int constants, but doesn't use a cast.)
 
102
 *
 
103
 ************************************************************************)
 
104
 
 
105
open Cil_types
 
106
open Cil
 
107
module E = Errormsg
 
108
module H = Hashtbl
 
109
 
 
110
(* For transformation #1. Stores all variable definitions in the file. *)
 
111
let varDefinitions: (varinfo, global) H.t = H.create 111
 
112
 
 
113
 
 
114
class canonicalizeVisitor = object(self)
 
115
  inherit nopCilVisitor
 
116
  val mutable currentFunction: fundec = Cil.dummyFunDec;
 
117
 
 
118
  (* A hashtable to prevent duplicate declarations. *)
 
119
  val alreadyDeclared: (varinfo, unit) H.t = H.create 111
 
120
  val alreadyDefined: (varinfo, unit) H.t = H.create 111
 
121
 
 
122
  (* move variable declarations around *)
 
123
  method vglob g = match g with
 
124
    GVar(v, ({init = Some _} as inito), l) ->
 
125
      (* A definition.  May have been moved to an earlier position. *)
 
126
      if H.mem alreadyDefined v then begin
 
127
        ignore (E.warn "Duplicate definition of %s at %a.\n"
 
128
                        (!Cil.output_ident v.vname) d_loc !currentLoc);
 
129
        ChangeTo [] (* delete from here. *)
 
130
      end else begin
 
131
        H.add alreadyDefined v ();
 
132
        if H.mem alreadyDeclared v then begin
 
133
          (* Change the earlier declaration to Extern *)
 
134
          let oldS = v.vstorage in
 
135
          ignore (E.log "changing storage of %s from %a\n"
 
136
                    (!Cil.output_ident v.vname) d_storage oldS);
 
137
          v.vstorage <- Extern;
 
138
          let newv = {v with vstorage = oldS} in
 
139
          ChangeDoChildrenPost([GVar(newv, inito, l)], (fun g -> g) )
 
140
        end else
 
141
          DoChildren
 
142
      end
 
143
  | GVar(v, {init=None}, l)
 
144
  | GVarDecl(v, l) when not (isFunctionType v.vtype) -> begin
 
145
      (* A declaration.  May have been moved to an earlier position. *)
 
146
      if H.mem alreadyDefined v || H.mem alreadyDeclared v then
 
147
        ChangeTo [] (* delete from here. *)
 
148
      else begin
 
149
        H.add alreadyDeclared v ();
 
150
        DoChildren
 
151
      end
 
152
  end
 
153
  | GFun(f, l) ->
 
154
      currentFunction <- f;
 
155
      DoChildren
 
156
  | _ ->
 
157
      DoChildren
 
158
 
 
159
(* #2. rename any identifiers whose names are C++ keywords *)
 
160
  method vvdec v =
 
161
    match v.vname with
 
162
    | "bool"
 
163
    | "catch"
 
164
    | "cdecl"
 
165
    | "class"
 
166
    | "const_cast"
 
167
    | "delete"
 
168
    | "dynamic_cast"
 
169
    | "explicit"
 
170
    | "export"
 
171
    | "false"
 
172
    | "friend"
 
173
    | "mutable"
 
174
    | "namespace"
 
175
    | "new"
 
176
    | "operator"
 
177
    | "pascal"
 
178
    | "private"
 
179
    | "protected"
 
180
    | "public"
 
181
    | "register"
 
182
    | "reinterpret_cast"
 
183
    | "static_cast"
 
184
    | "template"
 
185
    | "this"
 
186
    | "throw"
 
187
    | "true"
 
188
    | "try"
 
189
    | "typeid"
 
190
    | "typename"
 
191
    | "using"
 
192
    | "virtual"
 
193
    | "wchar_t"->
 
194
        v.vname <- v.vname ^ "__cil2cpp";
 
195
        DoChildren
 
196
    | _ -> DoChildren
 
197
 
 
198
  method vinst i =
 
199
(* #5. If an assignment or function call uses expressions as enum values,
 
200
   add an explicit cast. *)
 
201
    match i with
 
202
      Set (dest, exp, l) -> begin
 
203
        let typeOfDest = typeOfLval dest in
 
204
        match unrollType typeOfDest with
 
205
          TEnum _ -> (* add an explicit cast *)
 
206
            let newI = Set(dest, mkCast exp typeOfDest, l) in
 
207
            ChangeTo [newI]
 
208
        | _ -> SkipChildren
 
209
      end
 
210
    | Call (dest, f, args, l) -> begin
 
211
        let rt, formals, isva, attrs = splitFunctionType (typeOf f) in
 
212
        if isva then
 
213
          SkipChildren (* ignore vararg functions *)
 
214
        else
 
215
          match formals with
 
216
            Some formals' -> begin
 
217
              let newArgs = try
 
218
                (*Iterate over the arguments, looking for formals that
 
219
                   expect enum types, and insert casts where necessary. *)
 
220
                List.map2
 
221
                  (fun (actual: exp) (formalName, formalType, _) ->
 
222
                    match unrollType formalType with
 
223
                      TEnum _ -> mkCast actual formalType
 
224
                    | _ ->  actual)
 
225
                  args
 
226
                  formals'
 
227
              with Invalid_argument _ ->
 
228
                E.s (error "Number of arguments to %a doesn't match type.\n"
 
229
                       d_exp f)
 
230
              in
 
231
              let newI = Call(dest, f, newArgs, l) in
 
232
              ChangeTo [newI]
 
233
            end
 
234
          | None -> begin
 
235
  (* #4. No arguments were specified for this type.  To fix this, infer the
 
236
         type from the arguments that are used n this instruction, and insert
 
237
         a cast to that type.*)
 
238
              match f with
 
239
                Lval(Mem(fp), off) ->
 
240
                  let counter: int ref = ref 0 in
 
241
                  let newFormals = List.map
 
242
                      (fun (actual:exp) ->
 
243
                        incr counter;
 
244
                        let formalName = "a" ^ (string_of_int !counter) in
 
245
                        (formalName, typeOf actual, []))(* (name,type,attrs) *)
 
246
                          args in
 
247
                  let newFuncPtrType =
 
248
                    TPtr((TFun (rt, Some newFormals, false, attrs)), []) in
 
249
                  let newFuncPtr = Lval(Mem(mkCast fp newFuncPtrType), off) in
 
250
                  ChangeTo [Call(dest, newFuncPtr, args, l)]
 
251
              | _ ->
 
252
                  ignore (warn "cppcanon: %a has no specified arguments, but it's not a function pointer." d_exp f);
 
253
                  SkipChildren
 
254
          end
 
255
    end
 
256
    | _ -> SkipChildren
 
257
 
 
258
  method vinit (forg: varinfo) (off: offset) i =
 
259
(* #5. If an initializer uses expressions as enum values,
 
260
   add an explicit cast. *)
 
261
    match i with
 
262
      SingleInit e -> DoChildren (* we don't handle simple initializers here,
 
263
                                  because we don't know what type is expected.
 
264
                                  This should be done in vglob if needed. *)
 
265
    | CompoundInit(t, initList) ->
 
266
        let changed: bool ref = ref false in
 
267
        let initList' = List.map
 
268
            (* iterate over the list, adding casts for any expression that
 
269
               is expected to be an enum type. *)
 
270
          (function
 
271
              (Field(fi, off), SingleInit e) -> begin
 
272
                match unrollType fi.ftype with
 
273
                  TEnum _ -> (* add an explicit cast *)
 
274
                    let newE = mkCast e fi.ftype in
 
275
                    changed := true;
 
276
                    (Field(fi, off), SingleInit newE)
 
277
                | _ -> (* not enum, no cast needed *)
 
278
                    (Field(fi, off), SingleInit e)
 
279
              end
 
280
            | other ->
 
281
                   (* This is a more complicated initializer, and I don't think
 
282
                      it can have type enum.  It's children might, though. *)
 
283
                other)
 
284
            initList in
 
285
        if !changed then begin
 
286
          (* There may be other casts needed in other parts of the
 
287
             initialization, so do the children too. *)
 
288
          ChangeDoChildrenPost(CompoundInit(t, initList'), (fun x -> x))
 
289
        end else
 
290
          DoChildren
 
291
 
 
292
 
 
293
(* #5. If a function returns an enum type, add an explicit cast to the
 
294
       return type. *)
 
295
  method vstmt stmt =
 
296
    (match stmt.skind with
 
297
      Return (Some exp, l) -> begin
 
298
        let typeOfDest, _, _, _ =
 
299
          splitFunctionType currentFunction.svar.vtype in
 
300
        match unrollType typeOfDest with
 
301
          TEnum _ ->
 
302
            stmt.skind <- Return (Some (mkCast exp typeOfDest), l)
 
303
        | _ -> ()
 
304
      end
 
305
    | _ -> ());
 
306
    DoChildren
 
307
end (* class canonicalizeVisitor *)
 
308
 
 
309
 
 
310
 
 
311
(* Entry point for this extension *)
 
312
let canonicalize (f:file) =
 
313
  visitCilFile (new canonicalizeVisitor) f;
 
314
 
 
315
  (* #3. Finally, add some #defines to change C keywords to their C++
 
316
     equivalents: *)
 
317
  f.globals <-
 
318
    GText( "#ifdef __cplusplus\n"
 
319
          ^" #define __restrict\n" (* "restrict" doesn't work *)
 
320
          ^" #define __inline inline\n"
 
321
          ^"#endif")
 
322
    ::f.globals
 
323
 
 
324
 
 
325
 
 
326
let feature : featureDescr =
 
327
  { fd_name = "canonicalize";
 
328
    fd_enabled = ref false;
 
329
    fd_description = "fixing some C-isms so that the result is C++ compliant.";
 
330
    fd_extraopt = [];
 
331
    fd_doit = canonicalize;
 
332
    fd_post_check = true;
 
333
  }