CBMC
ansi_c_convert_type.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: SpecC Language Conversion
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "ansi_c_convert_type.h"
13 
14 #include <util/c_types.h>
15 #include <util/config.h>
16 #include <util/message.h>
17 #include <util/std_types.h>
18 #include <util/string_constant.h>
19 
20 #include "gcc_types.h"
21 
23 {
24  if(type.id()==ID_merged_type)
25  {
26  for(const typet &subtype : to_type_with_subtypes(type).subtypes())
27  read_rec(subtype);
28  }
29  else if(type.id()==ID_signed)
30  signed_cnt++;
31  else if(type.id()==ID_unsigned)
32  unsigned_cnt++;
33  else if(type.id()==ID_ptr32)
35  else if(type.id()==ID_ptr64)
37  else if(type.id()==ID_volatile)
39  else if(type.id()==ID_asm)
40  {
41  // These can have up to 5 subtypes; we only use the first one.
42  const auto &type_with_subtypes = to_type_with_subtypes(type);
43  if(
44  !type_with_subtypes.subtypes().empty() &&
45  type_with_subtypes.subtypes()[0].id() == ID_string_constant)
47  to_string_constant(type_with_subtypes.subtypes()[0]).value();
48  }
49  else if(
50  type.id() == ID_section && type.has_subtype() &&
51  to_type_with_subtype(type).subtype().id() == ID_string_constant)
52  {
55  }
56  else if(type.id()==ID_const)
58  else if(type.id()==ID_restrict)
60  else if(type.id()==ID_atomic)
62  else if(type.id()==ID_atomic_type_specifier)
63  {
64  // this gets turned into the qualifier, uh
66  read_rec(to_type_with_subtype(type).subtype());
67  }
68  else if(type.id()==ID_char)
69  char_cnt++;
70  else if(type.id()==ID_int)
71  int_cnt++;
72  else if(type.id()==ID_int8)
73  int8_cnt++;
74  else if(type.id()==ID_int16)
75  int16_cnt++;
76  else if(type.id()==ID_int32)
77  int32_cnt++;
78  else if(type.id()==ID_int64)
79  int64_cnt++;
80  else if(type.id()==ID_gcc_float16)
82  else if(type.id()==ID_gcc_float32)
84  else if(type.id()==ID_gcc_float32x)
86  else if(type.id()==ID_gcc_float64)
88  else if(type.id()==ID_gcc_float64x)
90  else if(type.id()==ID_gcc_float128)
92  else if(type.id()==ID_gcc_float128x)
94  else if(type.id()==ID_gcc_int128)
96  else if(type.id()==ID_gcc_attribute_mode)
97  {
98  gcc_attribute_mode=type;
99  }
100  else if(type.id()==ID_msc_based)
101  {
102  const exprt &as_expr=
103  static_cast<const exprt &>(static_cast<const irept &>(type));
104  msc_based = to_unary_expr(as_expr).op();
105  }
106  else if(type.id()==ID_custom_bv)
107  {
108  bv_cnt++;
109  const exprt &size_expr=
110  static_cast<const exprt &>(type.find(ID_size));
111 
112  bv_width=size_expr;
113  }
114  else if(type.id()==ID_custom_floatbv)
115  {
116  floatbv_cnt++;
117 
118  const exprt &size_expr=
119  static_cast<const exprt &>(type.find(ID_size));
120  const exprt &fsize_expr=
121  static_cast<const exprt &>(type.find(ID_f));
122 
123  bv_width=size_expr;
124  fraction_width=fsize_expr;
125  }
126  else if(type.id()==ID_custom_fixedbv)
127  {
128  fixedbv_cnt++;
129 
130  const exprt &size_expr=
131  static_cast<const exprt &>(type.find(ID_size));
132  const exprt &fsize_expr=
133  static_cast<const exprt &>(type.find(ID_f));
134 
135  bv_width=size_expr;
136  fraction_width=fsize_expr;
137  }
138  else if(type.id()==ID_short)
139  short_cnt++;
140  else if(type.id()==ID_long)
141  long_cnt++;
142  else if(type.id()==ID_double)
143  double_cnt++;
144  else if(type.id()==ID_float)
145  float_cnt++;
146  else if(type.id()==ID_c_bool)
147  c_bool_cnt++;
148  else if(type.id()==ID_proper_bool)
149  proper_bool_cnt++;
150  else if(type.id()==ID_complex)
151  complex_cnt++;
152  else if(type.id()==ID_static)
154  else if(type.id()==ID_thread_local)
156  else if(type.id()==ID_inline)
158  else if(type.id()==ID_extern)
160  else if(type.id()==ID_typedef)
162  else if(type.id()==ID_register)
164  else if(type.id()==ID_weak)
165  c_storage_spec.is_weak=true;
166  else if(type.id() == ID_used)
167  c_storage_spec.is_used = true;
168  else if(type.id()==ID_auto)
169  {
170  // ignore
171  }
172  else if(type.id()==ID_packed)
173  packed=true;
174  else if(type.id()==ID_aligned)
175  {
176  aligned=true;
177 
178  // may come with size or not
179  if(type.find(ID_size).is_nil())
180  alignment=exprt(ID_default);
181  else
182  alignment=static_cast<const exprt &>(type.find(ID_size));
183  }
184  else if(type.id()==ID_transparent_union)
185  {
187  }
188  else if(type.id() == ID_frontend_vector)
189  {
190  // note that this is not yet a vector_typet -- this is a size only
191  vector_size = static_cast<const constant_exprt &>(type.find(ID_size));
192  }
193  else if(type.id()==ID_void)
194  {
195  // we store 'void' as 'empty'
196  typet tmp=type;
197  tmp.id(ID_empty);
198  other.push_back(tmp);
199  }
200  else if(type.id()==ID_msc_declspec)
201  {
202  const exprt &as_expr=
203  static_cast<const exprt &>(static_cast<const irept &>(type));
204 
205  for(const auto &op : as_expr.operands())
206  {
207  // these are symbols
208  const irep_idt &id = op.get(ID_identifier);
209 
210  if(id==ID_thread)
212  else if(id=="align")
213  {
214  aligned=true;
215  alignment = to_unary_expr(op).op();
216  }
217  }
218  }
219  else if(type.id() == ID_nodiscard)
220  c_qualifiers.is_nodiscard = true;
221  else if(type.id()==ID_noreturn)
223  else if(type.id()==ID_constructor)
224  constructor=true;
225  else if(type.id()==ID_destructor)
226  destructor=true;
227  else if(
228  type.id() == ID_alias && type.has_subtype() &&
229  to_type_with_subtype(type).subtype().id() == ID_string_constant)
230  {
232  to_string_constant(to_type_with_subtype(type).subtype()).value();
233  }
234  else if(type.id()==ID_frontend_pointer)
235  {
236  // We turn ID_frontend_pointer to ID_pointer
237  // Pointers have a width, much like integers,
238  // which is added here.
239  pointer_typet tmp(
242  const irep_idt typedef_identifier=type.get(ID_C_typedef);
243  if(!typedef_identifier.empty())
244  tmp.set(ID_C_typedef, typedef_identifier);
245  other.push_back(tmp);
246  }
247  else if(type.id()==ID_pointer)
248  {
249  UNREACHABLE;
250  }
251  else if(type.id() == ID_C_spec_requires)
252  {
253  const exprt &as_expr =
254  static_cast<const exprt &>(static_cast<const irept &>(type));
255  c_requires.push_back(to_unary_expr(as_expr).op());
256  }
257  else if(type.id() == ID_C_spec_assigns)
258  {
259  const exprt &as_expr =
260  static_cast<const exprt &>(static_cast<const irept &>(type));
261 
262  for(const exprt &target : to_unary_expr(as_expr).op().operands())
263  c_assigns.push_back(target);
264  }
265  else if(type.id() == ID_C_spec_frees)
266  {
267  const exprt &as_expr =
268  static_cast<const exprt &>(static_cast<const irept &>(type));
269 
270  for(const exprt &target : to_unary_expr(as_expr).op().operands())
271  c_frees.push_back(target);
272  }
273  else if(type.id() == ID_C_spec_ensures)
274  {
275  const exprt &as_expr =
276  static_cast<const exprt &>(static_cast<const irept &>(type));
277  c_ensures.push_back(to_unary_expr(as_expr).op());
278  }
279  else
280  other.push_back(type);
281 }
282 
284 {
286 
287  type.clear();
288 
289  // first, do "other"
290 
291  if(!other.empty())
292  {
293  if(double_cnt || float_cnt || signed_cnt ||
297  gcc_float16_cnt ||
302  {
303  log.error().source_location = source_location;
304  log.error() << "illegal type modifier for defined type" << messaget::eom;
305  throw 0;
306  }
307 
308  // asm blocks (cf. regression/ansi-c/asm1) - ignore the asm
309  if(other.size()==2)
310  {
311  if(other.front().id()==ID_asm && other.back().id()==ID_empty)
312  other.pop_front();
313  else if(other.front().id()==ID_empty && other.back().id()==ID_asm)
314  other.pop_back();
315  }
316 
317  if(other.size()!=1)
318  {
319  log.error().source_location = source_location;
320  log.error() << "illegal combination of defined types" << messaget::eom;
321  throw 0;
322  }
323 
324  type.swap(other.front());
325 
326  // the contract expressions are meant for function types only
327  if(!c_requires.empty())
328  to_code_with_contract_type(type).c_requires() = std::move(c_requires);
329 
330  if(!c_assigns.empty())
331  to_code_with_contract_type(type).c_assigns() = std::move(c_assigns);
332 
333  if(!c_frees.empty())
334  to_code_with_contract_type(type).c_frees() = std::move(c_frees);
335 
336  if(!c_ensures.empty())
337  to_code_with_contract_type(type).c_ensures() = std::move(c_ensures);
338 
339  if(constructor || destructor)
340  {
341  if(constructor && destructor)
342  {
343  log.error().source_location = source_location;
344  log.error() << "combining constructor and destructor not supported"
345  << messaget::eom;
346  throw 0;
347  }
348 
349  typet *type_p=&type;
350  if(type.id()==ID_code)
351  type_p=&(to_code_type(type).return_type());
352 
353  else if(type_p->id()!=ID_empty)
354  {
355  log.error().source_location = source_location;
356  log.error() << "constructor and destructor required to be type void, "
357  << "found " << type_p->pretty() << messaget::eom;
358  throw 0;
359  }
360 
361  type_p->id(constructor ? ID_constructor : ID_destructor);
362  }
363  }
364  else if(constructor || destructor)
365  {
366  log.error().source_location = source_location;
367  log.error() << "constructor and destructor required to be type void, "
368  << "found " << type.pretty() << messaget::eom;
369  throw 0;
370  }
371  else if(gcc_float16_cnt ||
375  {
378  gcc_int128_cnt || bv_cnt ||
379  short_cnt || char_cnt)
380  {
381  log.error().source_location = source_location;
382  log.error() << "cannot combine integer type with floating-point type"
383  << messaget::eom;
384  throw 0;
385  }
386 
387  if(long_cnt+double_cnt+
392  {
393  log.error().source_location = source_location;
394  log.error() << "conflicting type modifiers" << messaget::eom;
395  throw 0;
396  }
397 
398  // _not_ the same as float, double, long double
399  if(gcc_float16_cnt)
400  type=gcc_float16_type();
401  else if(gcc_float32_cnt)
402  type=gcc_float32_type();
403  else if(gcc_float32x_cnt)
404  type=gcc_float32x_type();
405  else if(gcc_float64_cnt)
406  type=gcc_float64_type();
407  else if(gcc_float64x_cnt)
408  type=gcc_float64x_type();
409  else if(gcc_float128_cnt)
410  type=gcc_float128_type();
411  else if(gcc_float128x_cnt)
412  type=gcc_float128x_type();
413  else
414  UNREACHABLE;
415  }
416  else if(double_cnt || float_cnt)
417  {
421  short_cnt || char_cnt)
422  {
423  log.error().source_location = source_location;
424  log.error() << "cannot combine integer type with floating-point type"
425  << messaget::eom;
426  throw 0;
427  }
428 
429  if(double_cnt && float_cnt)
430  {
431  log.error().source_location = source_location;
432  log.error() << "conflicting type modifiers" << messaget::eom;
433  throw 0;
434  }
435 
436  if(long_cnt==0)
437  {
438  if(double_cnt!=0)
439  type=double_type();
440  else
441  type=float_type();
442  }
443  else if(long_cnt==1 || long_cnt==2)
444  {
445  if(double_cnt!=0)
446  type=long_double_type();
447  else
448  {
449  log.error().source_location = source_location;
450  log.error() << "conflicting type modifiers" << messaget::eom;
451  throw 0;
452  }
453  }
454  else
455  {
456  log.error().source_location = source_location;
457  log.error() << "illegal type modifier for float" << messaget::eom;
458  throw 0;
459  }
460  }
461  else if(c_bool_cnt)
462  {
466  char_cnt || long_cnt)
467  {
468  log.error().source_location = source_location;
469  log.error() << "illegal type modifier for C boolean type"
470  << messaget::eom;
471  throw 0;
472  }
473 
474  type=c_bool_type();
475  }
476  else if(proper_bool_cnt)
477  {
481  char_cnt || long_cnt)
482  {
483  log.error().source_location = source_location;
484  log.error() << "illegal type modifier for proper boolean type"
485  << messaget::eom;
486  throw 0;
487  }
488 
489  type.id(ID_bool);
490  }
491  else if(complex_cnt && !char_cnt && !signed_cnt && !unsigned_cnt &&
493  {
494  // the "default" for complex is double
495  type=double_type();
496  }
497  else if(char_cnt)
498  {
499  if(int_cnt || short_cnt || long_cnt ||
502  {
503  log.error().source_location = source_location;
504  log.error() << "illegal type modifier for char type" << messaget::eom;
505  throw 0;
506  }
507 
508  if(signed_cnt && unsigned_cnt)
509  {
510  log.error().source_location = source_location;
511  log.error() << "conflicting type modifiers" << messaget::eom;
512  throw 0;
513  }
514  else if(unsigned_cnt)
515  type=unsigned_char_type();
516  else if(signed_cnt)
517  type=signed_char_type();
518  else
519  type=char_type();
520  }
521  else
522  {
523  // it is integer -- signed or unsigned?
524 
525  bool is_signed=true; // default
526 
527  if(signed_cnt && unsigned_cnt)
528  {
529  log.error().source_location = source_location;
530  log.error() << "conflicting type modifiers" << messaget::eom;
531  throw 0;
532  }
533  else if(unsigned_cnt)
534  is_signed=false;
535  else if(signed_cnt)
536  is_signed=true;
537 
539  {
541  {
542  log.error().source_location = source_location;
543  log.error() << "conflicting type modifiers" << messaget::eom;
544  throw 0;
545  }
546 
547  if(int8_cnt)
548  if(is_signed)
549  type=signed_char_type();
550  else
551  type=unsigned_char_type();
552  else if(int16_cnt)
553  if(is_signed)
554  type=signed_short_int_type();
555  else
557  else if(int32_cnt)
558  if(is_signed)
559  type=signed_int_type();
560  else
561  type=unsigned_int_type();
562  else if(int64_cnt) // Visual Studio: equivalent to long long int
563  if(is_signed)
565  else
567  else
568  UNREACHABLE;
569  }
570  else if(gcc_int128_cnt)
571  {
572  if(is_signed)
573  type=gcc_signed_int128_type();
574  else
576  }
577  else if(bv_cnt)
578  {
579  // explicitly-given expression for width
580  type.id(is_signed?ID_custom_signedbv:ID_custom_unsignedbv);
581  type.set(ID_size, bv_width);
582  }
583  else if(floatbv_cnt)
584  {
585  type.id(ID_custom_floatbv);
586  type.set(ID_size, bv_width);
587  type.set(ID_f, fraction_width);
588  }
589  else if(fixedbv_cnt)
590  {
591  type.id(ID_custom_fixedbv);
592  type.set(ID_size, bv_width);
593  type.set(ID_f, fraction_width);
594  }
595  else if(short_cnt)
596  {
597  if(long_cnt || char_cnt)
598  {
599  log.error().source_location = source_location;
600  log.error() << "conflicting type modifiers" << messaget::eom;
601  throw 0;
602  }
603 
604  if(is_signed)
605  type=signed_short_int_type();
606  else
608  }
609  else if(long_cnt==0)
610  {
611  if(is_signed)
612  type=signed_int_type();
613  else
614  type=unsigned_int_type();
615  }
616  else if(long_cnt==1)
617  {
618  if(is_signed)
619  type=signed_long_int_type();
620  else
621  type=unsigned_long_int_type();
622  }
623  else if(long_cnt==2)
624  {
625  if(is_signed)
627  else
629  }
630  else
631  {
632  log.error().source_location = source_location;
633  log.error() << "illegal type modifier for integer type" << messaget::eom;
634  throw 0;
635  }
636  }
637 
639  set_attributes(type);
640 }
641 
644 {
645  if(vector_size.is_not_nil())
646  {
647  type_with_subtypet new_type(ID_frontend_vector, type);
648  new_type.set(ID_size, vector_size);
650  type=new_type;
651  }
652 
653  if(complex_cnt)
654  {
655  // These take more or less arbitrary subtypes.
656  complex_typet new_type(type);
658  type.swap(new_type);
659  }
660 }
661 
664 {
666  {
667  typet new_type=gcc_attribute_mode;
668  new_type.add_subtype() = type;
669  type.swap(new_type);
670  }
671 
672  c_qualifiers.write(type);
673 
674  if(packed)
675  type.set(ID_C_packed, true);
676 
677  if(aligned)
678  type.set(ID_C_alignment, alignment);
679 }
ANSI-C Language Conversion.
configt config
Definition: config.cpp:25
floatbv_typet float_type()
Definition: c_types.cpp:177
signedbv_typet signed_long_int_type()
Definition: c_types.cpp:72
signedbv_typet signed_char_type()
Definition: c_types.cpp:134
unsignedbv_typet unsigned_int_type()
Definition: c_types.cpp:36
unsignedbv_typet unsigned_long_long_int_type()
Definition: c_types.cpp:93
unsignedbv_typet unsigned_long_int_type()
Definition: c_types.cpp:86
signedbv_typet signed_int_type()
Definition: c_types.cpp:22
unsignedbv_typet unsigned_char_type()
Definition: c_types.cpp:127
bitvector_typet char_type()
Definition: c_types.cpp:106
signedbv_typet signed_long_long_int_type()
Definition: c_types.cpp:79
floatbv_typet long_double_type()
Definition: c_types.cpp:193
typet c_bool_type()
Definition: c_types.cpp:100
floatbv_typet double_type()
Definition: c_types.cpp:185
signedbv_typet signed_short_int_type()
Definition: c_types.cpp:29
unsignedbv_typet unsigned_short_int_type()
Definition: c_types.cpp:43
const code_with_contract_typet & to_code_with_contract_type(const typet &type)
Cast a typet to a code_with_contract_typet.
Definition: c_types.h:467
virtual void read_rec(const typet &type)
c_storage_spect c_storage_spec
exprt::operandst c_frees
exprt::operandst c_ensures
virtual void write(typet &type)
message_handlert & message_handler
virtual void set_attributes(typet &type) const
Add qualifiers and GCC attributes onto type.
exprt::operandst c_requires
source_locationt source_location
exprt::operandst c_assigns
virtual void build_type_with_subtype(typet &type) const
Build a vector or complex type with type as subtype.
std::list< typet > other
bool is_restricted
Definition: c_qualifiers.h:52
virtual void write(typet &src) const
bool is_transparent_union
Definition: c_qualifiers.h:59
irep_idt asm_label
const typet & return_type() const
Definition: std_types.h:689
const exprt::operandst & c_assigns() const
Definition: c_types.h:408
const exprt::operandst & c_requires() const
Definition: c_types.h:428
const exprt::operandst & c_frees() const
Definition: c_types.h:418
const exprt::operandst & c_ensures() const
Definition: c_types.h:438
Complex numbers made of pair of given subtype.
Definition: std_types.h:1130
struct configt::ansi_ct ansi_c
A constant literal expression.
Definition: std_expr.h:2995
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool empty() const
Definition: dstring.h:89
Base class for all expressions.
Definition: expr.h:56
const source_locationt & source_location() const
Definition: expr.h:231
operandst & operands()
Definition: expr.h:94
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition: irep.h:364
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:482
const irept & find(const irep_idt &name) const
Definition: irep.cpp:93
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:412
void clear()
Definition: irep.h:444
bool is_not_nil() const
Definition: irep.h:372
const irep_idt & id() const
Definition: irep.h:388
void swap(irept &irep)
Definition: irep.h:434
bool is_nil() const
Definition: irep.h:368
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:154
static eomt eom
Definition: message.h:289
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
Definition: pointer_expr.h:24
void value(const irep_idt &)
Type with a single subtype.
Definition: type.h:180
The type of an expression, extends irept.
Definition: type.h:29
const source_locationt & source_location() const
Definition: type.h:72
typet & add_subtype()
Definition: type.h:53
bool has_subtype() const
Definition: type.h:64
source_locationt & add_source_location()
Definition: type.h:77
const exprt & op() const
Definition: std_expr.h:391
floatbv_typet gcc_float32_type()
Definition: gcc_types.cpp:21
floatbv_typet gcc_float16_type()
Definition: gcc_types.cpp:13
floatbv_typet gcc_float64_type()
Definition: gcc_types.cpp:39
signedbv_typet gcc_signed_int128_type()
Definition: gcc_types.cpp:82
floatbv_typet gcc_float32x_type()
Definition: gcc_types.cpp:30
floatbv_typet gcc_float64x_type()
Definition: gcc_types.cpp:48
floatbv_typet gcc_float128x_type()
Definition: gcc_types.cpp:66
unsignedbv_typet gcc_unsigned_int128_type()
Definition: gcc_types.cpp:75
floatbv_typet gcc_float128_type()
Definition: gcc_types.cpp:57
double log(double x)
Definition: math.c:2776
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition: std_expr.h:426
Pre-defined types.
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:788
const string_constantt & to_string_constant(const exprt &expr)
std::size_t pointer_width
Definition: config.h:143
const type_with_subtypest & to_type_with_subtypes(const typet &type)
Definition: type.h:252
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:208
bool is_signed(const typet &t)
Convenience function – is the type signed?
Definition: util.cpp:45