diff --git a/src/kernel_internals/typing/mergecil.ml b/src/kernel_internals/typing/mergecil.ml index 8b515e1324e0a864d89e8defac41540c51606e0a..a120eb377d97ce076dd354d03df9501e65f2e98c 100644 --- a/src/kernel_internals/typing/mergecil.ml +++ b/src/kernel_internals/typing/mergecil.ml @@ -1191,113 +1191,112 @@ and matchCompInfo (oldfidx: int) (oldci: compinfo) let oldfidx = oldcinode.nfidx in let ci = cinode.ndata in let fidx = cinode.nfidx in - - match oldci.cfields, ci.cfields with - | _, None -> () (* new struct is not defined, just keep using the old one *) - | None, Some fields -> - (* old struct is not defined, but new one is. Use its fields. *) - oldci.cfields <- Some fields - | Some oldfields, Some fields -> - let old_len = List.length oldfields in - let len = List.length fields in - if old_len <> len then begin - let curLoc = CurrentLoc.get () in (* d_global blows this away.. *) - CurrentLoc.set curLoc; - let aggregate_name = if cstruct then "struct" else "union" in - let msg = Printf.sprintf - "different number of fields in %s %s and %s %s: %d != %d." - aggregate_name oldci.cname aggregate_name ci.cname - old_len len - in - raise (Failure msg) - end; - (* We check that they are defined in the same way. While doing this there - * might be recursion and we have to watch for going into an infinite - * loop. So we add the assumption that they are equal *) - let newrep, undo = union oldcinode cinode in - (* We check the fields but watch for Failure. We only do the check when - * the lengths are the same. Due to the code above this the other - * possibility is that one of the length is 0, in which case we reuse the - * old compinfo. *) - begin - try - (* must_check_offsets indicates that composite type attributes are - different, which may impact field offsets *) - let mustCheckOffsets = - if equal_attributes_for_merge ci.cattr oldci.cattr then false - else if equalModuloPackedAlign ci.cattr oldci.cattr then true - else raise - (Failure - (let attrs = drop_attributes_for_merge ci.cattr in - let oldattrs = drop_attributes_for_merge oldci.cattr in - (* we do not use Cil_datatype.Attributes.pretty because it - may not print some relevant attributes *) - let pp_attrs = - Pretty_utils.pp_list ~sep:", " Printer.pp_attribute - in - Format.asprintf - "different/incompatible composite type attributes: \ - [%a] vs [%a]" - pp_attrs attrs pp_attrs oldattrs)) - in - List.iter2 - (fun oldf f -> - checkFieldsEqualModuloPackedAlign ~mustCheckOffsets f oldf; - (* Make sure the types are compatible *) - (* Note: 6.2.7 §1 states that the names of the fields - should be the same. - We do not force this for now, but could do it. *) - let newtype = - combineTypes CombineOther oldfidx oldf.ftype fidx f.ftype - in - (* Change the type in the representative *) - oldf.ftype <- newtype) - oldfields fields - with Failure reason -> - (* Our assumption was wrong. Forget the isomorphism *) - undo (); - let fields_old = - Format.asprintf "%a" - Cil_printer.pp_global - (GCompTag(oldci, Cil_datatype.Location.unknown)) - in - let fields = - Format.asprintf "%a" - Cil_printer.pp_global - (GCompTag(ci, Cil_datatype.Location.unknown)) - in - let fullname_old = compFullName oldci in - let fullname = compFullName ci in - let msg = - match fullname_old = fullname, - fields_old = fields (* Could also use a special comparison *) - with - true, true -> - Format.asprintf - "Definitions of %s are not isomorphic. Reason follows:@\n@?%s" - fullname_old reason - | false, true -> - Format.asprintf - "%s and %s are not isomorphic. Reason follows:@\n@?%s" - fullname_old fullname reason - | true, false -> - Format.asprintf - "Definitions of %s are not isomorphic. \ - Reason follows:@\n@?%s@\n@?%s@?%s" - fullname_old reason - fields_old fields - | false, false -> - Format.asprintf - "%s and %s are not isomorphic. \ - Reason follows:@\n@?%s@\n@?%s@?%s" - fullname_old fullname reason - fields_old fields - in - raise (Failure msg) - end; - (* We get here when we succeeded checking that they are equal, or one of - * them was empty *) - newrep.ndata.cattr <- addAttributes oldci.cattr ci.cattr + (* We check that they are defined in the same way. While doing this there + * might be recursion and we have to watch for going into an infinite + * loop. So we add the assumption that they are equal *) + let newrep, undo = union oldcinode cinode in + (match oldci.cfields, ci.cfields with + | _, None -> () (* new struct is not defined, just keep using the old one *) + | None, Some fields -> + (* old struct is not defined, but new one is. Use its fields. *) + oldci.cfields <- Some fields + | Some oldfields, Some fields -> + let old_len = List.length oldfields in + let len = List.length fields in + if old_len <> len then begin + let curLoc = CurrentLoc.get () in (* d_global blows this away.. *) + CurrentLoc.set curLoc; + let aggregate_name = if cstruct then "struct" else "union" in + let msg = Printf.sprintf + "different number of fields in %s %s and %s %s: %d != %d." + aggregate_name oldci.cname aggregate_name ci.cname + old_len len + in + raise (Failure msg) + end; + (* We check the fields but watch for Failure. We only do the check when + * the lengths are the same. Due to the code above this the other + * possibility is that one of the length is 0, in which case we reuse the + * old compinfo. *) + begin + try + (* must_check_offsets indicates that composite type attributes are + different, which may impact field offsets *) + let mustCheckOffsets = + if equal_attributes_for_merge ci.cattr oldci.cattr then false + else if equalModuloPackedAlign ci.cattr oldci.cattr then true + else raise + (Failure + (let attrs = drop_attributes_for_merge ci.cattr in + let oldattrs = drop_attributes_for_merge oldci.cattr in + (* we do not use Cil_datatype.Attributes.pretty because it + may not print some relevant attributes *) + let pp_attrs = + Pretty_utils.pp_list ~sep:", " Printer.pp_attribute + in + Format.asprintf + "different/incompatible composite type attributes: \ + [%a] vs [%a]" + pp_attrs attrs pp_attrs oldattrs)) + in + List.iter2 + (fun oldf f -> + checkFieldsEqualModuloPackedAlign ~mustCheckOffsets f oldf; + (* Make sure the types are compatible *) + (* Note: 6.2.7 §1 states that the names of the fields + should be the same. + We do not force this for now, but could do it. *) + let newtype = + combineTypes CombineOther oldfidx oldf.ftype fidx f.ftype + in + (* Change the type in the representative *) + oldf.ftype <- newtype) + oldfields fields + with Failure reason -> + (* Our assumption was wrong. Forget the isomorphism *) + undo (); + let fields_old = + Format.asprintf "%a" + Cil_printer.pp_global + (GCompTag(oldci, Cil_datatype.Location.unknown)) + in + let fields = + Format.asprintf "%a" + Cil_printer.pp_global + (GCompTag(ci, Cil_datatype.Location.unknown)) + in + let fullname_old = compFullName oldci in + let fullname = compFullName ci in + let msg = + match fullname_old = fullname, + fields_old = fields (* Could also use a special comparison *) + with + true, true -> + Format.asprintf + "Definitions of %s are not isomorphic. Reason follows:@\n@?%s" + fullname_old reason + | false, true -> + Format.asprintf + "%s and %s are not isomorphic. Reason follows:@\n@?%s" + fullname_old fullname reason + | true, false -> + Format.asprintf + "Definitions of %s are not isomorphic. \ + Reason follows:@\n@?%s@\n@?%s@?%s" + fullname_old reason + fields_old fields + | false, false -> + Format.asprintf + "%s and %s are not isomorphic. \ + Reason follows:@\n@?%s@\n@?%s@?%s" + fullname_old fullname reason + fields_old fields + in + raise (Failure msg) + end); + (* We get here when we succeeded checking that they are equal, or one of + * them was empty *) + newrep.ndata.cattr <- addAttributes oldci.cattr ci.cattr end (* Match two enuminfos and throw a Failure if they do not match *) diff --git a/tests/syntax/oracle/typedef_struct.res.oracle b/tests/syntax/oracle/typedef_struct.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..8beec1c4be5b5c655b62cd00c7c000a396f463bd --- /dev/null +++ b/tests/syntax/oracle/typedef_struct.res.oracle @@ -0,0 +1,25 @@ +[kernel] Parsing typedef_struct_2.i (no preprocessing) +[kernel] Parsing typedef_struct.i (no preprocessing) +[kernel] Parsing typedef_struct_2.i (no preprocessing) +/* Generated by Frama-C */ +typedef struct foo foo; +struct foo { + int y ; +}; +foo *f(int x); + +extern foo *alloc(void); + +foo *f(int x) +{ + foo *__retres; + foo *f_0 = alloc(); + if (f_0->y == x) { + __retres = (foo *)0; + goto return_label; + } + __retres = f_0; + return_label: return __retres; +} + + diff --git a/tests/syntax/typedef_struct.i b/tests/syntax/typedef_struct.i new file mode 100644 index 0000000000000000000000000000000000000000..f376bbaa6a28ed1259b406ac2412b3b80e80dc50 --- /dev/null +++ b/tests/syntax/typedef_struct.i @@ -0,0 +1,19 @@ +/* run.config +OPT: %{dep:typedef_struct_2.i} @PTEST_FILE@ %{dep:typedef_struct_2.i} -print +*/ +typedef struct foo foo; +extern foo *alloc(void); + +foo* f(int x); + +struct foo +{ + int y; +}; + +foo* f(int x) +{ + foo* f = alloc(); + if (f->y == x) return 0; + return f; + } diff --git a/tests/syntax/typedef_struct_2.i b/tests/syntax/typedef_struct_2.i new file mode 100644 index 0000000000000000000000000000000000000000..507ac9cd50539a09a7146999520e2fedce85438e --- /dev/null +++ b/tests/syntax/typedef_struct_2.i @@ -0,0 +1,5 @@ +/* run.config + DONTRUN: main test is in typedef_struct.i +*/ +typedef struct foo foo; +foo* f(int);