1
(**************************************************************************)
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. *)
10
(* Redistribution and use in source and binary forms, with or without *)
11
(* modification, are permitted provided that the following conditions *)
14
(* 1. Redistributions of source code must retain the above copyright *)
15
(* notice, this list of conditions and the following disclaimer. *)
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. *)
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. *)
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. *)
38
(* File modified by CEA (Commissariat ļæ½ l'ļæ½nergie Atomique). *)
39
(**************************************************************************)
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.
49
* Redistribution and use in source and binary forms, with or without
50
* modification, are permitted provided that the following conditions are
53
* 1. Redistributions of source code must retain the above copyright
54
* notice, this list of conditions and the following disclaimer.
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.
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
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.
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.
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.
90
* #2) Any variables that use C++ keywords as identifiers are renamed.
92
* #3) __inline is #defined to inline, and __restrict is #defined to nothing.
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
100
* #5) Makes casts from int to enum types explicit. (CIL changes enum
101
* constants to int constants, but doesn't use a cast.)
103
************************************************************************)
110
(* For transformation #1. Stores all variable definitions in the file. *)
111
let varDefinitions: (varinfo, global) H.t = H.create 111
114
class canonicalizeVisitor = object(self)
115
inherit nopCilVisitor
116
val mutable currentFunction: fundec = Cil.dummyFunDec;
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
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. *)
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) )
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. *)
149
H.add alreadyDeclared v ();
154
currentFunction <- f;
159
(* #2. rename any identifiers whose names are C++ keywords *)
194
v.vname <- v.vname ^ "__cil2cpp";
199
(* #5. If an assignment or function call uses expressions as enum values,
200
add an explicit cast. *)
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
210
| Call (dest, f, args, l) -> begin
211
let rt, formals, isva, attrs = splitFunctionType (typeOf f) in
213
SkipChildren (* ignore vararg functions *)
216
Some formals' -> begin
218
(*Iterate over the arguments, looking for formals that
219
expect enum types, and insert casts where necessary. *)
221
(fun (actual: exp) (formalName, formalType, _) ->
222
match unrollType formalType with
223
TEnum _ -> mkCast actual formalType
227
with Invalid_argument _ ->
228
E.s (error "Number of arguments to %a doesn't match type.\n"
231
let newI = Call(dest, f, newArgs, l) in
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.*)
239
Lval(Mem(fp), off) ->
240
let counter: int ref = ref 0 in
241
let newFormals = List.map
244
let formalName = "a" ^ (string_of_int !counter) in
245
(formalName, typeOf actual, []))(* (name,type,attrs) *)
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)]
252
ignore (warn "cppcanon: %a has no specified arguments, but it's not a function pointer." d_exp f);
258
method vinit (forg: varinfo) (off: offset) i =
259
(* #5. If an initializer uses expressions as enum values,
260
add an explicit cast. *)
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. *)
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
276
(Field(fi, off), SingleInit newE)
277
| _ -> (* not enum, no cast needed *)
278
(Field(fi, off), SingleInit e)
281
(* This is a more complicated initializer, and I don't think
282
it can have type enum. It's children might, though. *)
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))
293
(* #5. If a function returns an enum type, add an explicit cast to the
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
302
stmt.skind <- Return (Some (mkCast exp typeOfDest), l)
307
end (* class canonicalizeVisitor *)
311
(* Entry point for this extension *)
312
let canonicalize (f:file) =
313
visitCilFile (new canonicalizeVisitor) f;
315
(* #3. Finally, add some #defines to change C keywords to their C++
318
GText( "#ifdef __cplusplus\n"
319
^" #define __restrict\n" (* "restrict" doesn't work *)
320
^" #define __inline inline\n"
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.";
331
fd_doit = canonicalize;
332
fd_post_check = true;