cprover
cpp_typecheck_resolve.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: C++ Language Type Checking
4 
5 Author: Daniel Kroening, kroening@cs.cmu.edu
6 
7 \*******************************************************************/
8 
11 
12 #include "cpp_typecheck_resolve.h"
13 
14 #include <cstdlib>
15 #include <algorithm>
16 
17 #include <util/std_types.h>
18 #include <util/std_expr.h>
19 #include <util/arith_tools.h>
20 #include <util/prefix.h>
21 
22 #include <util/c_types.h>
23 #include <ansi-c/string_constant.h>
25 
26 #include "cpp_typecheck.h"
27 #include "cpp_template_type.h"
28 #include "cpp_type2name.h"
29 #include "cpp_util.h"
30 #include "cpp_convert_type.h"
31 
33  cpp_typecheck(_cpp_typecheck)
34 {
35 }
36 
38  const cpp_scopest::id_sett &id_set,
39  const wantt want,
40  const cpp_typecheck_fargst &fargs,
41  resolve_identifierst &identifiers)
42 {
43  for(cpp_scopest::id_sett::const_iterator
44  it=id_set.begin();
45  it!=id_set.end();
46  it++)
47  {
48  const cpp_idt &identifier=**it;
49  exprt e=convert_identifier(identifier, want, fargs);
50 
51  if(e.is_not_nil())
52  {
53  if(e.id()==ID_type)
54  assert(e.type().is_not_nil());
55 
56  identifiers.push_back(e);
57  }
58  }
59 }
60 
62  resolve_identifierst &identifiers,
63  const cpp_template_args_non_tct &template_args,
64  const cpp_typecheck_fargst &fargs)
65 {
66  resolve_identifierst old_identifiers;
67  old_identifiers.swap(identifiers);
68 
69  for(resolve_identifierst::const_iterator
70  it=old_identifiers.begin();
71  it!=old_identifiers.end();
72  it++)
73  {
74  exprt e=*it;
75  apply_template_args(e, template_args, fargs);
76 
77  if(e.is_not_nil())
78  {
79  if(e.id()==ID_type)
80  assert(e.type().is_not_nil());
81 
82  identifiers.push_back(e);
83  }
84  }
85 }
86 
89  resolve_identifierst &identifiers,
90  const cpp_typecheck_fargst &fargs)
91 {
92  resolve_identifierst old_identifiers;
93  old_identifiers.swap(identifiers);
94 
95  for(resolve_identifierst::const_iterator
96  it=old_identifiers.begin();
97  it!=old_identifiers.end();
98  it++)
99  {
100  exprt e=guess_function_template_args(*it, fargs);
101 
102  if(e.is_not_nil())
103  {
104  assert(e.id()!=ID_type);
105  identifiers.push_back(e);
106  }
107  }
108 
109  disambiguate_functions(identifiers, fargs);
110 
111  // there should only be one left, or we have failed to disambiguate
112  if(identifiers.size()==1)
113  {
114  // instantiate that one
115  exprt e=*identifiers.begin();
116  assert(e.id()==ID_template_function_instance);
117 
118  const symbolt &template_symbol=
119  cpp_typecheck.lookup(e.type().get(ID_C_template));
120 
121  const cpp_template_args_tct &template_args=
122  to_cpp_template_args_tc(e.type().find(ID_C_template_arguments));
123 
124  // Let's build the instance.
125 
126  const symbolt &new_symbol=
129  template_symbol,
130  template_args,
131  template_args);
132 
133  identifiers.clear();
134  identifiers.push_back(
135  symbol_exprt(new_symbol.name, new_symbol.type));
136  }
137 }
138 
140  resolve_identifierst &identifiers)
141 {
142  resolve_identifierst old_identifiers;
143  old_identifiers.swap(identifiers);
144 
145  for(resolve_identifierst::const_iterator
146  it=old_identifiers.begin();
147  it!=old_identifiers.end();
148  it++)
149  {
150  if(!cpp_typecheck.follow(it->type()).get_bool(ID_is_template))
151  identifiers.push_back(*it);
152  }
153 }
154 
156  resolve_identifierst &identifiers)
157 {
158  resolve_identifierst old_identifiers;
159  old_identifiers.swap(identifiers);
160 
161  std::set<irep_idt> ids;
162  std::set<exprt> other;
163 
164  for(resolve_identifierst::const_iterator
165  it=old_identifiers.begin();
166  it!=old_identifiers.end();
167  it++)
168  {
169  irep_idt id;
170 
171  if(it->id()==ID_symbol)
172  id=it->get(ID_identifier);
173  else if(it->id()==ID_type && it->type().id()==ID_symbol)
174  id=it->type().get(ID_identifier);
175 
176  if(id=="")
177  {
178  if(other.insert(*it).second)
179  identifiers.push_back(*it);
180  }
181  else
182  {
183  if(ids.insert(id).second)
184  identifiers.push_back(*it);
185  }
186  }
187 }
188 
190  const cpp_idt &identifier)
191 {
192  // look up the parameter in the template map
194 
195  if(e.is_nil() ||
196  (e.id()==ID_type && e.type().is_nil()))
197  {
199  cpp_typecheck.error() << "internal error: template parameter "
200  << "without instance:\n"
201  << identifier << messaget::eom;
202  throw 0;
203  }
204 
206 
207  return e;
208 }
209 
211  const cpp_idt &identifier,
212  const wantt want,
213  const cpp_typecheck_fargst &fargs)
214 {
216  return convert_template_parameter(identifier);
217 
218  exprt e;
219 
220  if(identifier.is_member &&
221  !identifier.is_constructor &&
222  !identifier.is_static_member)
223  {
224  // a regular struct or union member
225 
226  const symbolt &compound_symbol=
228 
229  assert(compound_symbol.type.id()==ID_struct ||
230  compound_symbol.type.id()==ID_union);
231 
232  const struct_union_typet &struct_union_type=
233  to_struct_union_type(compound_symbol.type);
234 
235  const exprt component=
236  struct_union_type.get_component(identifier.identifier);
237 
238  const typet &type=component.type();
239  assert(type.is_not_nil());
240 
242  {
243  e=type_exprt(type);
244  }
245  else if(identifier.id_class==cpp_scopet::id_classt::SYMBOL)
246  {
247  // A non-static, non-type member.
248  // There has to be an object.
249  e=exprt(ID_member);
250  e.set(ID_component_name, identifier.identifier);
252 
253  exprt object;
254  object.make_nil();
255 
256  #if 0
257  std::cout << "I: " << identifier.class_identifier
258  << " "
260  this_class_identifier << '\n';
261  #endif
262 
263  const exprt &this_expr=
265 
266  if(fargs.has_object)
267  {
268  // the object is given to us in fargs
269  assert(!fargs.operands.empty());
270  object=fargs.operands.front();
271  }
272  else if(this_expr.is_not_nil())
273  {
274  // use this->...
275  assert(this_expr.type().id()==ID_pointer);
276  object=exprt(ID_dereference, this_expr.type().subtype());
277  object.copy_to_operands(this_expr);
278  object.type().set(ID_C_constant,
279  this_expr.type().subtype().get_bool(ID_C_constant));
280  object.set(ID_C_lvalue, true);
281  object.add_source_location()=source_location;
282  }
283 
284  // check if the member can be applied to the object
285  typet object_type=cpp_typecheck.follow(object.type());
286 
287  if(object_type.id()==ID_struct ||
288  object_type.id()==ID_union)
289  {
290  if(!has_component_rec(
291  to_struct_union_type(object_type),
292  identifier.identifier,
293  cpp_typecheck))
294  object.make_nil(); // failed!
295  }
296  else
297  object.make_nil();
298 
299  if(object.is_not_nil())
300  {
301  // we got an object
302  e.move_to_operands(object);
303 
304  bool old_value=cpp_typecheck.disable_access_control;
308  }
309  else
310  {
311  // this has to be a method
312  if(identifier.is_method)
314  else
315  e.make_nil();
316  }
317  }
318  }
319  else
320  {
321  const symbolt &symbol=
322  cpp_typecheck.lookup(identifier.identifier);
323 
324  if(symbol.is_type)
325  {
326  e=type_exprt();
327 
328  if(symbol.is_macro) // includes typedefs
329  {
330  e.type()=symbol.type;
331  assert(symbol.type.is_not_nil());
332  }
333  else if(symbol.type.id()==ID_c_enum)
334  {
335  e.type()=c_enum_tag_typet(symbol.name);
336  }
337  else // will need to do struct, union
338  {
339  e.type()=symbol_typet(symbol.name);
340  }
341  }
342  else if(symbol.is_macro)
343  {
344  e=symbol.value;
345  assert(e.is_not_nil());
346  }
347  else
348  {
349  typet followed_type=symbol.type;
350  bool constant=followed_type.get_bool(ID_C_constant);
351 
352  while(followed_type.id()==ID_symbol)
353  {
354  typet tmp=cpp_typecheck.lookup(followed_type).type;
355  followed_type=tmp;
356  constant |= followed_type.get_bool(ID_C_constant);
357  }
358 
359  if(constant &&
360  symbol.value.is_not_nil() &&
361  is_number(followed_type) &&
362  symbol.value.id() == ID_constant)
363  {
364  e=symbol.value;
365  }
366  else
367  {
368  e=cpp_symbol_expr(symbol);
369  }
370  }
371  }
372 
374 
375  return e;
376 }
377 
379  resolve_identifierst &identifiers,
380  const wantt want)
381 {
382  resolve_identifierst old_identifiers;
383  old_identifiers.swap(identifiers);
384 
385  for(resolve_identifierst::const_iterator
386  it=old_identifiers.begin();
387  it!=old_identifiers.end();
388  it++)
389  {
390  bool match=false;
391 
392  switch(want)
393  {
394  case wantt::TYPE:
395  match=(it->id()==ID_type);
396  break;
397 
398  case wantt::VAR:
399  match=(it->id()!=ID_type);
400  break;
401 
402  case wantt::BOTH:
403  match=true;
404  break;
405 
406  default:
407  assert(false);
408  }
409 
410  if(match)
411  identifiers.push_back(*it);
412  }
413 }
414 
416  resolve_identifierst &identifiers,
417  const cpp_typecheck_fargst &fargs)
418 {
419  if(!fargs.in_use)
420  return;
421 
422  resolve_identifierst old_identifiers;
423  old_identifiers.swap(identifiers);
424 
425  identifiers.clear();
426 
427  // put in the ones that match precisely
428  for(resolve_identifierst::const_iterator
429  it=old_identifiers.begin();
430  it!=old_identifiers.end();
431  it++)
432  {
433  unsigned distance;
434  if(disambiguate_functions(*it, distance, fargs))
435  if(distance<=0)
436  identifiers.push_back(*it);
437  }
438 }
439 
441  resolve_identifierst &identifiers,
442  const cpp_typecheck_fargst &fargs)
443 {
444  resolve_identifierst old_identifiers;
445  old_identifiers.swap(identifiers);
446 
447  // sort according to distance
448  std::multimap<std::size_t, exprt> distance_map;
449 
450  for(resolve_identifierst::const_iterator
451  it=old_identifiers.begin();
452  it!=old_identifiers.end();
453  it++)
454  {
455  unsigned args_distance;
456 
457  if(disambiguate_functions(*it, args_distance, fargs))
458  {
459  std::size_t template_distance=0;
460 
461  if(it->type().get(ID_C_template)!="")
462  template_distance=it->type().
463  find(ID_C_template_arguments).find(ID_arguments).get_sub().size();
464 
465  // we give strong preference to functions that have
466  // fewer template arguments
467  std::size_t total_distance=
468  // NOLINTNEXTLINE(whitespace/operators)
469  1000*template_distance+args_distance;
470 
471  distance_map.insert(
472  std::pair<std::size_t, exprt>(total_distance, *it));
473  }
474  }
475 
476  identifiers.clear();
477 
478  // put in the top ones
479  if(!distance_map.empty())
480  {
481  std::size_t distance=distance_map.begin()->first;
482 
483  for(std::multimap<std::size_t, exprt>::const_iterator
484  it=distance_map.begin();
485  it!=distance_map.end() && it->first==distance;
486  it++)
487  identifiers.push_back(it->second);
488  }
489 
490  if(identifiers.size()>1 && fargs.in_use)
491  {
492  // try to further disambiguate functions
493 
494  for(resolve_identifierst::iterator
495  it1=identifiers.begin();
496  it1!=identifiers.end();
497  it1++)
498  {
499  if(it1->type().id()!=ID_code)
500  continue;
501 
502  const code_typet &f1=
503  to_code_type(it1->type());
504 
505  for(resolve_identifierst::iterator it2=
506  identifiers.begin();
507  it2!=identifiers.end();
508  ) // no it2++
509  {
510  if(it1 == it2)
511  {
512  it2++;
513  continue;
514  }
515 
516  if(it2->type().id()!=ID_code)
517  {
518  it2++;
519  continue;
520  }
521 
522  const code_typet &f2 =
523  to_code_type(it2->type());
524 
525  // TODO: may fail when using ellipsis
526  assert(f1.parameters().size() == f2.parameters().size());
527 
528  bool f1_better=true;
529  bool f2_better=true;
530 
531  for(std::size_t i=0;
532  i<f1.parameters().size() && (f1_better || f2_better);
533  i++)
534  {
535  typet type1=f1.parameters()[i].type();
536  typet type2=f2.parameters()[i].type();
537 
538  if(type1 == type2)
539  continue;
540 
541  if(is_reference(type1) != is_reference(type2))
542  continue;
543 
544  if(type1.id()==ID_pointer)
545  {
546  typet tmp=type1.subtype();
547  type1=tmp;
548  }
549 
550  if(type2.id()==ID_pointer)
551  {
552  typet tmp=type2.subtype();
553  type2=tmp;
554  }
555 
556  const typet &followed1=cpp_typecheck.follow(type1);
557  const typet &followed2=cpp_typecheck.follow(type2);
558 
559  if(followed1.id() != ID_struct || followed2.id() != ID_struct)
560  continue;
561 
562  const struct_typet &struct1=to_struct_type(followed1);
563  const struct_typet &struct2=to_struct_type(followed2);
564 
565  if(f1_better && cpp_typecheck.subtype_typecast(struct1, struct2))
566  {
567  f2_better=false;
568  }
569  else if(f2_better && cpp_typecheck.subtype_typecast(struct2, struct1))
570  {
571  f1_better=false;
572  }
573  }
574 
575  resolve_identifierst::iterator prev_it=it2;
576  it2++;
577 
578  if(f1_better && !f2_better)
579  identifiers.erase(prev_it);
580  }
581  }
582  }
583 }
584 
586  resolve_identifierst &identifiers)
587 {
588  resolve_identifierst new_identifiers;
589 
590  resolve_identifierst::iterator next;
591 
592  for(resolve_identifierst::iterator
593  it=identifiers.begin();
594  it!=identifiers.end();
595  it++)
596  {
597  if(it->id()!=ID_type)
598  {
599  // already an expression
600  new_identifiers.push_back(*it);
601  continue;
602  }
603 
604  const typet &symbol_type=
605  cpp_typecheck.follow(it->type());
606 
607  // is it a POD?
608 
609  if(cpp_typecheck.cpp_is_pod(symbol_type))
610  {
611  // there are two pod constructors:
612 
613  // 1. no arguments, default initialization
614  {
615  code_typet t1;
616  t1.return_type()=it->type();
617  exprt pod_constructor1("pod_constructor", t1);
618  new_identifiers.push_back(pod_constructor1);
619  }
620 
621  // 2. one argument, copy/conversion
622  {
623  code_typet t2;
624  t2.return_type()=it->type();
625  t2.parameters().resize(1);
626  t2.parameters()[0].type()=it->type();
627  exprt pod_constructor2("pod_constructor", t2);
628  new_identifiers.push_back(pod_constructor2);
629  }
630 
631  // enums, in addition, can also be constructed from int
632  if(symbol_type.id()==ID_c_enum_tag)
633  {
634  code_typet t3;
635  t3.return_type()=it->type();
636  t3.parameters().resize(1);
637  t3.parameters()[0].type()=signed_int_type();
638  exprt pod_constructor3("pod_constructor", t3);
639  new_identifiers.push_back(pod_constructor3);
640  }
641  }
642  else if(symbol_type.id()==ID_struct)
643  {
644  const struct_typet &struct_type=to_struct_type(symbol_type);
645 
646  const struct_typet::componentst &components =
647  struct_type.components();
648 
649  // go over components
650  for(struct_typet::componentst::const_iterator
651  itc=components.begin();
652  itc!=components.end();
653  itc++)
654  {
655  const struct_typet::componentt &component=*itc;
656  const typet &type=component.type();
657 
658  if(component.get_bool(ID_from_base))
659  continue;
660 
661  if(type.find(ID_return_type).id()==ID_constructor)
662  {
663  const symbolt &symb =
664  cpp_typecheck.lookup(component.get_name());
665  exprt e=cpp_symbol_expr(symb);
666  e.type()=type;
667  new_identifiers.push_back(e);
668  }
669  }
670  }
671  }
672 
673  identifiers.swap(new_identifiers);
674 }
675 
677  const irep_idt &base_name,
678  const cpp_template_args_non_tct &template_args)
679 {
680  exprt dest;
681 
682  const cpp_template_args_non_tct::argumentst &arguments=
683  template_args.arguments();
684 
685  if(base_name==ID_unsignedbv ||
686  base_name==ID_signedbv)
687  {
688  if(arguments.size()!=1)
689  {
692  << base_name << " expects one template argument, but got "
693  << arguments.size() << messaget::eom;
694  throw 0;
695  }
696 
697  const exprt &argument=arguments.front();
698 
699  if(argument.id()==ID_type)
700  {
703  << base_name << " expects one integer template argument, "
704  << "but got type" << messaget::eom;
705  throw 0;
706  }
707 
708  mp_integer i;
709  if(to_integer(argument, i))
710  {
712  cpp_typecheck.error() << "template argument must be constant"
713  << messaget::eom;
714  throw 0;
715  }
716 
717  if(i<1)
718  {
721  << "template argument must be greater than zero"
722  << messaget::eom;
723  throw 0;
724  }
725 
726  dest=type_exprt(typet(base_name));
727  dest.type().set(ID_width, integer2string(i));
728  }
729  else if(base_name==ID_fixedbv)
730  {
731  if(arguments.size()!=2)
732  {
735  << base_name << " expects two template arguments, but got "
736  << arguments.size() << messaget::eom;
737  throw 0;
738  }
739 
740  const exprt &argument0=arguments[0];
741  const exprt &argument1=arguments[1];
742 
743  if(argument0.id()==ID_type)
744  {
747  << base_name << " expects two integer template arguments, "
748  << "but got type" << messaget::eom;
749  throw 0;
750  }
751 
752  if(argument1.id()==ID_type)
753  {
756  << base_name << " expects two integer template arguments, "
757  << "but got type" << messaget::eom;
758  throw 0;
759  }
760 
761  mp_integer width, integer_bits;
762 
763  if(to_integer(argument0, width))
764  {
766  cpp_typecheck.error() << "template argument must be constant"
767  << messaget::eom;
768  throw 0;
769  }
770 
771  if(to_integer(argument1, integer_bits))
772  {
774  cpp_typecheck.error() << "template argument must be constant"
775  << messaget::eom;
776  throw 0;
777  }
778 
779  if(width<1)
780  {
783  << "template argument must be greater than zero"
784  << messaget::eom;
785  throw 0;
786  }
787 
788  if(integer_bits<0)
789  {
792  << "template argument must be greater or equal zero"
793  << messaget::eom;
794  throw 0;
795  }
796 
797  if(integer_bits>width)
798  {
801  << "template argument must be smaller or equal width"
802  << messaget::eom;
803  throw 0;
804  }
805 
806  dest=type_exprt(typet(base_name));
807  dest.type().set(ID_width, integer2string(width));
808  dest.type().set(ID_integer_bits, integer2string(integer_bits));
809  }
810  else if(base_name==ID_integer)
811  {
812  if(!arguments.empty())
813  {
816  << base_name << " expects no template arguments"
817  << messaget::eom;
818  throw 0;
819  }
820 
821  dest=type_exprt(typet(base_name));
822  }
823  else if(has_prefix(id2string(base_name), "constant_infinity"))
824  {
825  // ok, but type missing
826  dest=exprt(ID_infinity, size_type());
827  }
828  else if(base_name=="dump_scopes")
829  {
830  dest=exprt(ID_constant, typet(ID_empty));
831  cpp_typecheck.warning() << "Scopes in location "
835  }
836  else if(base_name=="current_scope")
837  {
838  dest=exprt(ID_constant, typet(ID_empty));
839  cpp_typecheck.warning() << "Scope in location " << source_location
840  << ": " << original_scope->prefix
841  << messaget::eom;
842  }
843  else if(base_name=="size_t")
844  {
845  dest=type_exprt(size_type());
846  }
847  else if(base_name=="ssize_t")
848  {
850  }
851  else
852  {
854  cpp_typecheck.error() << "unknown built-in identifier: "
855  << base_name << messaget::eom;
856  throw 0;
857  }
858 
859  return dest;
860 }
861 
866  const cpp_namet &cpp_name,
867  irep_idt &base_name,
868  cpp_template_args_non_tct &template_args)
869 {
870  assert(cpp_name.id()==ID_cpp_name);
871  assert(!cpp_name.get_sub().empty());
872 
874  source_location=cpp_name.source_location();
875 
876  irept::subt::const_iterator pos=cpp_name.get_sub().begin();
877 
878  bool recursive=true;
879 
880  // check if we need to go to the root scope
881  if(pos->id()=="::")
882  {
883  pos++;
885  recursive=false;
886  }
887 
888  std::string final_base_name="";
889  template_args.make_nil();
890 
891  while(pos!=cpp_name.get_sub().end())
892  {
893  if(pos->id()==ID_name)
894  final_base_name+=pos->get_string(ID_identifier);
895  else if(pos->id()==ID_template_args)
896  template_args=to_cpp_template_args_non_tc(*pos);
897  else if(pos->id()=="::")
898  {
900 
901  if(template_args.is_not_nil())
902  {
904  final_base_name,
907  id_set);
908 
909  // std::cout << "S: "
910  // << cpp_typecheck.cpp_scopes.current_scope().identifier
911  // << '\n';
912  // cpp_typecheck.cpp_scopes.current_scope().print(std::cout);
913  // std::cout << "X: " << id_set.size() << '\n';
914 
915  symbol_typet instance=
916  disambiguate_template_classes(final_base_name, id_set, template_args);
917 
919 
920  // the "::" triggers template elaboration
922 
925 
926  template_args.make_nil();
927  }
928  else
929  {
931  final_base_name,
933  id_set);
934 
936 
937  if(id_set.empty())
938  {
941  cpp_typecheck.error() << "scope `" << final_base_name
942  << "' not found" << messaget::eom;
943  throw 0;
944  }
945  else if(id_set.size()>=2)
946  {
949  cpp_typecheck.error() << "scope `"
950  << final_base_name << "' is ambiguous"
951  << messaget::eom;
952  throw 0;
953  }
954 
955  assert(id_set.size()==1);
956 
958 
959  // the "::" triggers template elaboration
961  {
962  symbol_typet instance(
965  }
966  }
967 
968  // we start from fresh
969  final_base_name.clear();
970  }
971  else if(pos->id()==ID_operator)
972  {
973  final_base_name+="operator";
974 
975  irept::subt::const_iterator next=pos+1;
976  assert(next != cpp_name.get_sub().end());
977 
978  if(next->id() == ID_cpp_name ||
979  next->id() == ID_pointer ||
980  next->id() == ID_int ||
981  next->id() == ID_char ||
982  next->id() == ID_bool ||
983  next->id() == ID_merged_type)
984  {
985  // it's a cast operator
986  irept next_ir=*next;
987  typet op_name;
988  op_name.swap(next_ir);
989  cpp_typecheck.typecheck_type(op_name);
990  final_base_name+="("+cpp_type2name(op_name)+")";
991  pos++;
992  }
993  }
994  else
995  final_base_name+=pos->id_string();
996 
997  pos++;
998  }
999 
1000  base_name=final_base_name;
1001 
1003 }
1004 
1007  const irep_idt &base_name,
1008  const cpp_scopest::id_sett &id_set,
1009  const cpp_template_args_non_tct &full_template_args)
1010 {
1011  if(id_set.empty())
1012  {
1015  cpp_typecheck.error() << "template scope `" << base_name
1016  << "' not found" << messaget::eom;
1017  throw 0;
1018  }
1019 
1020  std::set<irep_idt> primary_templates;
1021 
1022  for(cpp_scopest::id_sett::const_iterator
1023  it=id_set.begin();
1024  it!=id_set.end();
1025  it++)
1026  {
1027  const irep_idt id=(*it)->identifier;
1028  const symbolt &s=cpp_typecheck.lookup(id);
1029  if(!s.type.get_bool(ID_is_template))
1030  continue;
1031  const cpp_declarationt &cpp_declaration=to_cpp_declaration(s.type);
1032  if(!cpp_declaration.is_class_template())
1033  continue;
1034  irep_idt specialization_of=cpp_declaration.get_specialization_of();
1035  if(specialization_of!="")
1036  primary_templates.insert(specialization_of);
1037  else
1038  primary_templates.insert(id);
1039  }
1040 
1041  assert(!primary_templates.empty());
1042 
1043  if(primary_templates.size()>=2)
1044  {
1047  cpp_typecheck.error() << "template scope `" << base_name
1048  << "' is ambiguous" << messaget::eom;
1049  throw 0;
1050  }
1051 
1052  assert(primary_templates.size()==1);
1053 
1054  const symbolt &primary_template_symbol=
1055  cpp_typecheck.lookup(*primary_templates.begin());
1056 
1057  // We typecheck the template arguments in the context
1058  // of the original scope!
1059  cpp_template_args_tct full_template_args_tc;
1060 
1061  {
1063 
1065 
1066  // use template type of 'primary template'
1067  full_template_args_tc=
1070  primary_template_symbol,
1071  full_template_args);
1072  // go back to where we used to be
1073  }
1074 
1075  // find any matches
1076 
1077  std::vector<matcht> matches;
1078 
1079  // the baseline
1080  matches.push_back(
1081  matcht(full_template_args_tc, full_template_args_tc,
1082  primary_template_symbol.name));
1083 
1084  for(cpp_scopest::id_sett::const_iterator
1085  it=id_set.begin();
1086  it!=id_set.end();
1087  it++)
1088  {
1089  const irep_idt id=(*it)->identifier;
1090  const symbolt &s=cpp_typecheck.lookup(id);
1091 
1092  irep_idt specialization_of=s.type.get("specialization_of");
1093  if(specialization_of=="")
1094  continue;
1095 
1096  const cpp_declarationt &cpp_declaration=
1098 
1099  const cpp_template_args_non_tct &partial_specialization_args=
1100  cpp_declaration.partial_specialization_args();
1101 
1102  // alright, set up template arguments as 'unassigned'
1103 
1106 
1108  cpp_declaration.template_type());
1109 
1110  // iterate over template instance
1111  assert(full_template_args_tc.arguments().size()==
1112  partial_specialization_args.arguments().size());
1113 
1114  // we need to do this in the right scope
1115 
1116  cpp_scopet *template_scope=
1117  static_cast<cpp_scopet *>(
1119 
1120  if(template_scope==nullptr)
1121  {
1123  cpp_typecheck.error() << "template identifier: " << id << '\n'
1124  << "class template instantiation error"
1125  << messaget::eom;
1126  throw 0;
1127  }
1128 
1129  // enter the scope of the template
1130  cpp_typecheck.cpp_scopes.go_to(*template_scope);
1131 
1132  for(std::size_t i=0; i<full_template_args_tc.arguments().size(); i++)
1133  {
1134  if(full_template_args_tc.arguments()[i].id()==ID_type)
1135  guess_template_args(partial_specialization_args.arguments()[i].type(),
1136  full_template_args_tc.arguments()[i].type());
1137  else
1138  guess_template_args(partial_specialization_args.arguments()[i],
1139  full_template_args_tc.arguments()[i]);
1140  }
1141 
1142  // see if that has worked out
1143 
1144  cpp_template_args_tct guessed_template_args=
1146  cpp_declaration.template_type());
1147 
1148  if(!guessed_template_args.has_unassigned())
1149  {
1150  // check: we can now typecheck the partial_specialization_args
1151 
1152  cpp_template_args_tct partial_specialization_args_tc=
1155  primary_template_symbol,
1156  partial_specialization_args);
1157 
1158  // if these match the arguments, we have a match
1159 
1160  assert(partial_specialization_args_tc.arguments().size()==
1161  full_template_args_tc.arguments().size());
1162 
1163  if(partial_specialization_args_tc==
1164  full_template_args_tc)
1165  {
1166  matches.push_back(matcht(
1167  guessed_template_args, full_template_args_tc, id));
1168  }
1169  }
1170  }
1171 
1172  assert(!matches.empty());
1173 
1174  std::sort(matches.begin(), matches.end());
1175 
1176  #if 0
1177  for(std::vector<matcht>::const_iterator
1178  m_it=matches.begin();
1179  m_it!=matches.end();
1180  m_it++)
1181  {
1182  std::cout << "M: " << m_it->cost
1183  << " " << m_it->id << '\n';
1184  }
1185 
1186  std::cout << '\n';
1187  #endif
1188 
1189  const matcht &match=*matches.begin();
1190 
1191  const symbolt &choice=
1192  cpp_typecheck.lookup(match.id);
1193 
1194  #if 0
1195  // build instance
1196  const symbolt &instance=
1199  choice,
1200  match.specialization_args,
1201  match.full_args);
1202 
1203  if(instance.type.id()!=ID_struct &&
1204  instance.type.id()!=ID_incomplete_struct)
1205  {
1207  cpp_typecheck.str << "template `"
1208  << base_name << "' is not a class";
1209  throw 0;
1210  }
1211 
1212  symbol_typet result(instance.name);
1214 
1215  return result;
1216  #else
1217 
1218  // build instance
1219  const symbolt &instance=
1222  choice,
1223  match.specialization_args,
1224  match.full_args);
1225 
1226  symbol_typet result(instance.name);
1228 
1229  return result;
1230  #endif
1231 }
1232 
1234  const cpp_namet &cpp_name)
1235 {
1236  irep_idt base_name;
1237  cpp_template_args_non_tct template_args;
1238  template_args.make_nil();
1239 
1241  resolve_scope(cpp_name, base_name, template_args);
1242 
1244  bool qualified=cpp_name.is_qualified();
1245 
1247 
1249  base_name,
1251  id_set);
1252 
1254 
1255  if(id_set.empty())
1256  {
1259  << "namespace `"
1260  << base_name << "' not found" << messaget::eom;
1261  throw 0;
1262  }
1263  else if(id_set.size()==1)
1264  {
1265  cpp_idt &id=**id_set.begin();
1266  return (cpp_scopet &)id;
1267  }
1268  else
1269  {
1272  << "namespace `"
1273  << base_name << "' is ambiguous" << messaget::eom;
1274  throw 0;
1275  }
1276 }
1277 
1279  const irep_idt &base_name,
1280  const resolve_identifierst &identifiers,
1281  std::ostream &out)
1282 {
1283  for(resolve_identifierst::const_iterator
1284  it=identifiers.begin();
1285  it!=identifiers.end();
1286  it++)
1287  {
1288  const exprt &id_expr=*it;
1289 
1290  out << " ";
1291 
1292  if(id_expr.id()==ID_type)
1293  {
1294  out << "type " << cpp_typecheck.to_string(id_expr.type());
1295  }
1296  else
1297  {
1298  irep_idt id;
1299 
1300  if(id_expr.type().get_bool(ID_is_template))
1301  out << "template ";
1302 
1303  if(id_expr.id()==ID_member)
1304  {
1305  out << "member ";
1306  id="."+id2string(base_name);
1307  }
1308  else if(id_expr.id()=="pod_constructor")
1309  {
1310  out << "constructor ";
1311  id="";
1312  }
1313  else if(id_expr.id()==ID_template_function_instance)
1314  {
1315  out << "symbol ";
1316  }
1317  else
1318  {
1319  out << "symbol ";
1320  id=cpp_typecheck.to_string(id_expr);
1321  }
1322 
1323  if(id_expr.type().get_bool(ID_is_template))
1324  {
1325  }
1326  else if(id_expr.type().id()==ID_code)
1327  {
1328  const code_typet &code_type=to_code_type(id_expr.type());
1329  const typet &return_type=code_type.return_type();
1330  const code_typet::parameterst &parameters=code_type.parameters();
1331  out << cpp_typecheck.to_string(return_type);
1332  out << " " << id << "(";
1333 
1334  for(code_typet::parameterst::const_iterator
1335  it=parameters.begin(); it!=parameters.end(); it++)
1336  {
1337  const typet &parameter_type=it->type();
1338 
1339  if(it!=parameters.begin())
1340  out << ", ";
1341 
1342  out << cpp_typecheck.to_string(parameter_type);
1343  }
1344 
1345  if(code_type.has_ellipsis())
1346  {
1347  if(!parameters.empty())
1348  out << ", ";
1349  out << "...";
1350  }
1351 
1352  out << ")";
1353  }
1354  else
1355  out << id << ": " << cpp_typecheck.to_string(id_expr.type());
1356 
1357  if(id_expr.id()==ID_symbol)
1358  {
1359  const symbolt &symbol=cpp_typecheck.lookup(to_symbol_expr(id_expr));
1360  out << " (" << symbol.location << ")";
1361  }
1362  else if(id_expr.id()==ID_template_function_instance)
1363  {
1364  const symbolt &symbol=
1365  cpp_typecheck.lookup(id_expr.type().get(ID_C_template));
1366  out << " (" << symbol.location << ")";
1367  }
1368  }
1369 
1370  out << '\n';
1371  }
1372 }
1373 
1375  const cpp_namet &cpp_name,
1376  const wantt want,
1377  const cpp_typecheck_fargst &fargs,
1378  bool fail_with_exception)
1379 {
1380  irep_idt base_name;
1381  cpp_template_args_non_tct template_args;
1382  template_args.make_nil();
1383 
1386 
1387  // this changes the scope
1388  resolve_scope(cpp_name, base_name, template_args);
1389 
1391  bool qualified=cpp_name.is_qualified();
1392 
1393  // do __CPROVER scope
1394  if(qualified)
1395  {
1397  return do_builtin(base_name, template_args);
1398  }
1399  else
1400  {
1401  if(base_name=="__func__" ||
1402  base_name=="__FUNCTION__" ||
1403  base_name=="__PRETTY_FUNCTION__")
1404  {
1405  // __func__ is an ANSI-C standard compliant hack to get the function name
1406  // __FUNCTION__ and __PRETTY_FUNCTION__ are GCC-specific
1407  string_constantt s;
1410  return s;
1411  }
1412  }
1413 
1415 
1416  cpp_scopet::lookup_kindt lookup_kind=
1418 
1419  if(template_args.is_nil())
1421  base_name, lookup_kind, id_set);
1422  else
1424  base_name, lookup_kind, cpp_idt::id_classt::TEMPLATE, id_set);
1425 
1426  // Argument-dependent name lookup
1427  #if 0
1428  // not clear what this is good for
1429  if(!qualified && !fargs.has_object)
1430  resolve_with_arguments(id_set, base_name, fargs);
1431  #endif
1432 
1433  if(id_set.empty())
1434  {
1435  if(!fail_with_exception)
1436  return nil_exprt();
1437 
1440 
1441  if(qualified)
1442  {
1444  << "symbol `"
1445  << base_name << "' not found";
1446 
1448  cpp_typecheck.error() << " in root scope";
1449  else
1450  cpp_typecheck.error() << " in scope `"
1452  << "'";
1453  }
1454  else
1455  {
1457  << "symbol `"
1458  << base_name << "' is unknown";
1459  }
1460 
1462  // cpp_typecheck.cpp_scopes.get_root_scope().print(std::cout);
1463  // cpp_typecheck.cpp_scopes.current_scope().print(std::cout);
1464  throw 0;
1465  }
1466 
1467  resolve_identifierst identifiers;
1468 
1469  if(template_args.is_not_nil())
1470  {
1471  // first figure out if we are doing functions/methods or
1472  // classes
1473  bool have_classes=false, have_methods=false;
1474 
1475  for(cpp_scopest::id_sett::const_iterator
1476  it=id_set.begin();
1477  it!=id_set.end();
1478  it++)
1479  {
1480  const irep_idt id=(*it)->identifier;
1481  const symbolt &s=cpp_typecheck.lookup(id);
1482  assert(s.type.get_bool(ID_is_template));
1484  have_classes=true;
1485  else
1486  have_methods=true;
1487  }
1488 
1489  if(want==wantt::BOTH && have_classes && have_methods)
1490  {
1491  if(!fail_with_exception)
1492  return nil_exprt();
1493 
1497  << "template symbol `"
1498  << base_name << "' is ambiguous" << messaget::eom;
1499  throw 0;
1500  }
1501 
1502  if(want==wantt::TYPE || have_classes)
1503  {
1504  typet instance=
1505  disambiguate_template_classes(base_name, id_set, template_args);
1506  identifiers.push_back(exprt(ID_type, instance));
1507  }
1508  else
1509  {
1510  // methods and functions
1512  id_set, want, fargs, identifiers);
1513 
1515  identifiers, template_args, fargs);
1516  }
1517  }
1518  else
1519  {
1521  id_set, want, fargs, identifiers);
1522  }
1523 
1524  // change types into constructors if we want a constructor
1525  if(want==wantt::VAR)
1526  make_constructors(identifiers);
1527 
1528  filter(identifiers, want);
1529 
1530  #if 0
1531  std::cout << "P0 " << base_name << " " << identifiers.size() << "\n";
1532  show_identifiers(base_name, identifiers, std::cout);
1533  std::cout << "\n";
1534  #endif
1535 
1536  exprt result;
1537 
1538  // We disambiguate functions
1539  resolve_identifierst new_identifiers=identifiers;
1540 
1541  remove_templates(new_identifiers);
1542 
1543  #if 0
1544  std::cout << "P1 " << base_name << " " << new_identifiers.size() << "\n";
1545  show_identifiers(base_name, new_identifiers, std::cout);
1546  std::cout << "\n";
1547  #endif
1548 
1549  // we only want _exact_ matches, without templates!
1550  exact_match_functions(new_identifiers, fargs);
1551 
1552  #if 0
1553  std::cout << "P2 " << base_name << " " << new_identifiers.size() << "\n";
1554  show_identifiers(base_name, new_identifiers, std::cout);
1555  std::cout << "\n";
1556  #endif
1557 
1558  // no exact matches? Try again with function template guessing.
1559  if(new_identifiers.empty())
1560  {
1561  new_identifiers=identifiers;
1562 
1563  if(template_args.is_nil())
1564  {
1565  guess_function_template_args(new_identifiers, fargs);
1566 
1567  if(new_identifiers.empty())
1568  new_identifiers=identifiers;
1569  }
1570 
1571  disambiguate_functions(new_identifiers, fargs);
1572 
1573  #if 0
1574  std::cout << "P3 " << base_name << " " << new_identifiers.size() << "\n";
1575  show_identifiers(base_name, new_identifiers, std::cout);
1576  std::cout << "\n";
1577  #endif
1578  }
1579 
1580  remove_duplicates(new_identifiers);
1581 
1582  #if 0
1583  std::cout << "P4 " << base_name << " " << new_identifiers.size() << "\n";
1584  show_identifiers(base_name, new_identifiers, std::cout);
1585  std::cout << "\n";
1586  #endif
1587 
1588  if(new_identifiers.size()==1)
1589  {
1590  result=*new_identifiers.begin();
1591  }
1592  else
1593  {
1594  // nothing or too many
1595  if(!fail_with_exception)
1596  return nil_exprt();
1597 
1598  if(new_identifiers.empty())
1599  {
1602  << "found no match for symbol `" << base_name
1603  << "', candidates are:\n";
1604  show_identifiers(base_name, identifiers, cpp_typecheck.error());
1605  }
1606  else
1607  {
1610  << "symbol `" << base_name
1611  << "' does not uniquely resolve:\n";
1612  show_identifiers(base_name, new_identifiers, cpp_typecheck.error());
1613 
1614  #if 0
1615  exprt e1=*new_identifiers.begin();
1616  exprt e2=*(++new_identifiers.begin());
1617  cpp_typecheck.str << "e1==e2: " << (e1==e2) << '\n';
1618  cpp_typecheck.str << "e1.type==e2.type: " << (e1.type()==e2.type())
1619  << '\n';
1620  cpp_typecheck.str << "e1.id()==e2.id(): " << (e1.id()==e2.id())
1621  << '\n';
1622  cpp_typecheck.str << "e1.iden==e2.iden: "
1623  << (e1.get(ID_identifier)==e2.get(ID_identifier))
1624  << '\n';
1625  cpp_typecheck.str << "e1.iden:: " << e1.get(ID_identifier) << '\n';
1626  cpp_typecheck.str << "e2.iden:: " << e2.get(ID_identifier) << '\n';
1627  #endif
1628  }
1629 
1630  if(fargs.in_use)
1631  {
1632  cpp_typecheck.error() << "\nargument types:\n";
1633 
1634  for(exprt::operandst::const_iterator
1635  it=fargs.operands.begin();
1636  it!=fargs.operands.end();
1637  it++)
1638  {
1639  cpp_typecheck.error() << " "
1640  << cpp_typecheck.to_string(it->type())
1641  << '\n';
1642  }
1643  }
1644 
1645  if(!cpp_typecheck.instantiation_stack.empty())
1646  {
1648  }
1649 
1651  throw 0;
1652  }
1653 
1654  // we do some checks before we return
1655  if(result.get_bool("#not_accessible"))
1656  {
1657  #if 0
1658  if(!fail_with_exception)
1659  return nil_exprt();
1660 
1662  cpp_typecheck.str
1663  << "error: member `" << result.get("component_name").c_str()
1664  << "' is not accessible";
1665  throw 0;
1666  #endif
1667  }
1668 
1669  switch(want)
1670  {
1671  case wantt::VAR:
1672  if(result.id()==ID_type && !cpp_typecheck.cpp_is_pod(result.type()))
1673  {
1674  if(!fail_with_exception)
1675  return nil_exprt();
1676 
1678 
1680  << "error: expected expression, but got type `"
1681  << cpp_typecheck.to_string(result.type()) << "'"
1682  << messaget::eom;
1683 
1684  throw 0;
1685  }
1686  break;
1687 
1688  case wantt::TYPE:
1689  if(result.id()!=ID_type)
1690  {
1691  if(!fail_with_exception)
1692  return nil_exprt();
1693 
1695 
1697  << "error: expected type, but got expression `"
1698  << cpp_typecheck.to_string(result) << "'" << messaget::eom;
1699 
1700  throw 0;
1701  }
1702  break;
1703 
1704  default:
1705  {
1706  }
1707  }
1708 
1709  return result;
1710 }
1711 
1713  const exprt &template_expr,
1714  const exprt &desired_expr)
1715 {
1716  if(template_expr.id()==ID_cpp_name)
1717  {
1718  const cpp_namet &cpp_name=
1719  to_cpp_name(template_expr);
1720 
1721  if(!cpp_name.is_qualified())
1722  {
1724 
1725  cpp_template_args_non_tct template_args;
1726  irep_idt base_name;
1727  resolve_scope(cpp_name, base_name, template_args);
1728 
1731  base_name, cpp_scopet::RECURSIVE, id_set);
1732 
1733  // alright, rummage through these
1734  for(cpp_scopest::id_sett::const_iterator it=id_set.begin();
1735  it!=id_set.end();
1736  it++)
1737  {
1738  const cpp_idt &id=**it;
1739  // template parameter?
1741  {
1742  // see if unassigned
1743  exprt &e=cpp_typecheck.template_map.expr_map[id.identifier];
1744  if(e.id()==ID_unassigned)
1745  {
1746  typet old_type=e.type();
1747  e=desired_expr;
1748  if(e.type()!=old_type)
1749  e.make_typecast(old_type);
1750  }
1751  }
1752  }
1753  }
1754  }
1755 }
1756 
1758  const typet &template_type,
1759  const typet &desired_type)
1760 {
1761  // look at
1762  // http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/topic/
1763  // com.ibm.xlcpp8a.doc/language/ref/template_argument_deduction.htm
1764 
1765  // T
1766  // const T
1767  // volatile T
1768  // T&
1769  // T*
1770  // T[10]
1771  // A<T>
1772  // C(*)(T)
1773  // T(*)()
1774  // T(*)(U)
1775  // T C::*
1776  // C T::*
1777  // T U::*
1778  // T (C::*)()
1779  // C (T::*)()
1780  // D (C::*)(T)
1781  // C (T::*)(U)
1782  // T (C::*)(U)
1783  // T (U::*)()
1784  // T (U::*)(V)
1785  // E[10][i]
1786  // B<i>
1787  // TT<T>
1788  // TT<i>
1789  // TT<C>
1790 
1791  #if 0
1792  std::cout << "TT: " << template_type.pretty() << '\n';
1793  std::cout << "DT: " << desired_type.pretty() << '\n';
1794  #endif
1795 
1796  if(template_type.id()==ID_cpp_name)
1797  {
1798  // we only care about cpp_names that are template parameters!
1799  const cpp_namet &cpp_name=to_cpp_name(template_type);
1800 
1802 
1803  if(cpp_name.has_template_args())
1804  {
1805  // this could be something like my_template<T>, and we need
1806  // to match 'T'. Then 'desired_type' has to be a template instance.
1807 
1808  // TODO
1809  }
1810  else
1811  {
1812  // template parameters aren't qualified
1813  if(!cpp_name.is_qualified())
1814  {
1815  irep_idt base_name;
1816  cpp_template_args_non_tct template_args;
1817  resolve_scope(cpp_name, base_name, template_args);
1818 
1821  base_name, cpp_scopet::RECURSIVE, id_set);
1822 
1823  // alright, rummage through these
1824  for(cpp_scopest::id_sett::const_iterator
1825  it=id_set.begin();
1826  it!=id_set.end();
1827  it++)
1828  {
1829  const cpp_idt &id=**it;
1830 
1831  // template argument?
1833  {
1834  // see if unassigned
1835  typet &t=cpp_typecheck.template_map.type_map[id.identifier];
1836  if(t.id()==ID_unassigned)
1837  {
1838  t=desired_type;
1839 
1840  // remove const, volatile (these can be added in the call)
1841  t.remove(ID_C_constant);
1842  t.remove(ID_C_volatile);
1843  #if 0
1844  std::cout << "ASSIGN " << id.identifier << " := "
1845  << cpp_typecheck.to_string(desired_type) << '\n';
1846  #endif
1847  }
1848  }
1849  }
1850  }
1851  }
1852  }
1853  else if(template_type.id()==ID_merged_type)
1854  {
1855  // look at subtypes
1856  for(typet::subtypest::const_iterator
1857  it=template_type.subtypes().begin();
1858  it!=template_type.subtypes().end();
1859  it++)
1860  {
1861  guess_template_args(*it, desired_type);
1862  }
1863  }
1864  else if(is_reference(template_type) ||
1865  is_rvalue_reference(template_type))
1866  {
1867  guess_template_args(template_type.subtype(), desired_type);
1868  }
1869  else if(template_type.id()==ID_pointer)
1870  {
1871  const typet &desired_type_followed=
1872  cpp_typecheck.follow(desired_type);
1873 
1874  if(desired_type_followed.id()==ID_pointer)
1876  template_type.subtype(), desired_type_followed.subtype());
1877  }
1878  else if(template_type.id()==ID_array)
1879  {
1880  const typet &desired_type_followed=
1881  cpp_typecheck.follow(desired_type);
1882 
1883  if(desired_type_followed.id()==ID_array)
1884  {
1885  // look at subtype first
1887  template_type.subtype(),
1888  desired_type_followed.subtype());
1889 
1890  // size (e.g., buffer size guessing)
1892  to_array_type(template_type).size(),
1893  to_array_type(desired_type_followed).size());
1894  }
1895  }
1896 }
1897 
1900  const exprt &expr,
1901  const cpp_typecheck_fargst &fargs)
1902 {
1903  typet tmp=expr.type();
1905 
1906  if(!tmp.get_bool(ID_is_template))
1907  return nil_exprt(); // not a template
1908 
1909  assert(expr.id()==ID_symbol);
1910 
1911  // a template is always a declaration
1912  const cpp_declarationt &cpp_declaration=
1913  to_cpp_declaration(tmp);
1914 
1915  // Class templates require explicit template arguments,
1916  // no guessing!
1917  if(cpp_declaration.is_class_template())
1918  return nil_exprt();
1919 
1920  // we need function arguments for guessing
1921  if(fargs.operands.empty())
1922  return nil_exprt(); // give up
1923 
1924  // We need to guess in the case of function templates!
1925 
1926  irep_idt template_identifier=
1928 
1929  const symbolt &template_symbol=
1930  cpp_typecheck.lookup(template_identifier);
1931 
1932  // alright, set up template arguments as 'unassigned'
1933 
1935 
1937  cpp_declaration.template_type());
1938 
1939  // there should be exactly one declarator
1940  assert(cpp_declaration.declarators().size()==1);
1941 
1942  const cpp_declaratort &function_declarator=
1943  cpp_declaration.declarators().front();
1944 
1945  // and that needs to have function type
1946  if(function_declarator.type().id()!=ID_function_type)
1947  {
1950  << "expected function type for function template"
1951  << messaget::eom;
1952  throw 0;
1953  }
1954 
1955  cpp_save_scopet cpp_saved_scope(cpp_typecheck.cpp_scopes);
1956 
1957  // we need the template scope
1958  cpp_scopet *template_scope=
1959  static_cast<cpp_scopet *>(
1960  cpp_typecheck.cpp_scopes.id_map[template_identifier]);
1961 
1962  if(template_scope==nullptr)
1963  {
1965  cpp_typecheck.error() << "template identifier: "
1966  << template_identifier << '\n'
1967  << "function template instantiation error"
1968  << messaget::eom;
1969  throw 0;
1970  }
1971 
1972  // enter the scope of the template
1973  cpp_typecheck.cpp_scopes.go_to(*template_scope);
1974 
1975  // walk through the function parameters
1976  const irept::subt &parameters=
1977  function_declarator.type().find(ID_parameters).get_sub();
1978 
1979  exprt::operandst::const_iterator it=fargs.operands.begin();
1980  for(const auto &parameter : parameters)
1981  {
1982  if(it==fargs.operands.end())
1983  break;
1984 
1985  if(parameter.id()==ID_cpp_declaration)
1986  {
1987  const cpp_declarationt &arg_declaration=
1988  to_cpp_declaration(parameter);
1989 
1990  // again, there should be one declarator
1991  assert(arg_declaration.declarators().size()==1);
1992 
1993  // turn into type
1994  typet arg_type=
1995  arg_declaration.declarators().front().
1996  merge_type(arg_declaration.type());
1997 
1998  // We only convert the arg_type,
1999  // and don't typecheck it -- that could cause all
2000  // sorts of trouble.
2001  cpp_convert_plain_type(arg_type);
2002 
2003  guess_template_args(arg_type, it->type());
2004  }
2005 
2006  ++it;
2007  }
2008 
2009  // see if that has worked out
2010 
2011  cpp_template_args_tct template_args=
2013  cpp_declaration.template_type());
2014 
2015  if(template_args.has_unassigned())
2016  return nil_exprt(); // give up
2017 
2018  // Build the type of the function.
2019 
2020  typet function_type=
2021  function_declarator.merge_type(cpp_declaration.type());
2022 
2023  cpp_typecheck.typecheck_type(function_type);
2024 
2025  // Remember that this was a template
2026 
2027  function_type.set(ID_C_template, template_symbol.name);
2028  function_type.set(ID_C_template_arguments, template_args);
2029 
2030  // Seems we got an instance for all parameters. Let's return that.
2031 
2032  exprt template_function_instance(
2033  ID_template_function_instance, function_type);
2034 
2035  return template_function_instance;
2036 }
2037 
2039  exprt &expr,
2040  const cpp_template_args_non_tct &template_args_non_tc,
2041  const cpp_typecheck_fargst &fargs)
2042 {
2043  if(expr.id()!=ID_symbol)
2044  return; // templates are always symbols
2045 
2046  const symbolt &template_symbol=
2047  cpp_typecheck.lookup(expr.get(ID_identifier));
2048 
2049  if(!template_symbol.type.get_bool(ID_is_template))
2050  return;
2051 
2052  #if 0
2053  if(template_args_non_tc.is_nil())
2054  {
2055  // no arguments, need to guess
2056  guess_function_template_args(expr, fargs);
2057  return;
2058  }
2059  #endif
2060 
2061  // We typecheck the template arguments in the context
2062  // of the original scope!
2063  cpp_template_args_tct template_args_tc;
2064 
2065  {
2067 
2069 
2070  template_args_tc=
2073  template_symbol,
2074  template_args_non_tc);
2075  // go back to where we used to be
2076  }
2077 
2078  // We never try 'unassigned' template arguments.
2079  if(template_args_tc.has_unassigned())
2080  assert(false);
2081 
2082  // a template is always a declaration
2083  const cpp_declarationt &cpp_declaration=
2084  to_cpp_declaration(template_symbol.type);
2085 
2086  // is it a class template or function template?
2087  if(cpp_declaration.is_class_template())
2088  {
2089  const symbolt &new_symbol=
2092  template_symbol,
2093  template_args_tc,
2094  template_args_tc);
2095 
2096  expr=exprt(ID_type, symbol_typet(new_symbol.name));
2098  }
2099  else
2100  {
2101  // must be a function, maybe method
2102  const symbolt &new_symbol=
2105  template_symbol,
2106  template_args_tc,
2107  template_args_tc);
2108 
2109  // check if it is a method
2110  const code_typet &code_type=to_code_type(new_symbol.type);
2111 
2112  if(!code_type.parameters().empty() &&
2113  code_type.parameters()[0].get(ID_C_base_name)==ID_this)
2114  {
2115  // do we have an object?
2116  if(fargs.has_object)
2117  {
2118  const symbolt &type_symb=
2120  fargs.operands.begin()->type().get(ID_identifier));
2121 
2122  assert(type_symb.type.id()==ID_struct);
2123 
2124  const struct_typet &struct_type=
2125  to_struct_type(type_symb.type);
2126 
2127  assert(struct_type.has_component(new_symbol.name));
2128  member_exprt member(code_type);
2129  member.set_component_name(new_symbol.name);
2130  member.struct_op()=*fargs.operands.begin();
2131  member.add_source_location()=source_location;
2132  expr.swap(member);
2133  return;
2134  }
2135  }
2136 
2137  expr=cpp_symbol_expr(new_symbol);
2139  }
2140 }
2141 
2143  const exprt &expr,
2144  unsigned &args_distance,
2145  const cpp_typecheck_fargst &fargs)
2146 {
2147  args_distance=0;
2148 
2149  if(expr.type().id()!=ID_code || !fargs.in_use)
2150  return true;
2151 
2152  const code_typet &type=to_code_type(expr.type());
2153 
2154  if(expr.id()==ID_member ||
2155  type.return_type().id() == ID_constructor)
2156  {
2157  // if it's a member, but does not have an object yet,
2158  // we add one
2159  if(!fargs.has_object)
2160  {
2161  const code_typet::parameterst &parameters=type.parameters();
2162  const code_typet::parametert &parameter=parameters.front();
2163 
2164  assert(parameter.get(ID_C_base_name)==ID_this);
2165 
2166  if(type.return_type().id() == ID_constructor)
2167  {
2168  // it's a constructor
2169  const typet &object_type=parameter.type().subtype();
2170  exprt object(ID_symbol, object_type);
2171  object.set(ID_C_lvalue, true);
2172 
2173  cpp_typecheck_fargst new_fargs(fargs);
2174  new_fargs.add_object(object);
2175  return new_fargs.match(type, args_distance, cpp_typecheck);
2176  }
2177  else
2178  {
2179  if(expr.type().get_bool("#is_operator") &&
2180  fargs.operands.size() == parameters.size())
2181  {
2182  return fargs.match(type, args_distance, cpp_typecheck);
2183  }
2184 
2185  cpp_typecheck_fargst new_fargs(fargs);
2186  new_fargs.add_object(expr.op0());
2187 
2188  return new_fargs.match(type, args_distance, cpp_typecheck);
2189  }
2190  }
2191  }
2192  else if(fargs.has_object)
2193  {
2194  // if it's not a member then we shall remove the object
2195  cpp_typecheck_fargst new_fargs(fargs);
2196  new_fargs.remove_object();
2197 
2198  return new_fargs.match(type, args_distance, cpp_typecheck);
2199  }
2200 
2201  return fargs.match(type, args_distance, cpp_typecheck);
2202 }
2203 
2205  cpp_scopest::id_sett &id_set)
2206 {
2207  cpp_scopest::id_sett new_set;
2208 
2209  // std::cout << "FILTER\n";
2210 
2211  // We only want scopes!
2212  for(cpp_scopest::id_sett::const_iterator
2213  it=id_set.begin();
2214  it!=id_set.end();
2215  it++)
2216  {
2217  cpp_idt &id=**it;
2218 
2219  if(id.is_class() || id.is_enum() || id.is_namespace())
2220  {
2221  // std::cout << "X1\n";
2222  assert(id.is_scope);
2223  new_set.insert(&id);
2224  }
2225  else if(id.is_typedef())
2226  {
2227  // std::cout << "X2\n";
2228  irep_idt identifier=id.identifier;
2229 
2230  if(id.is_member)
2231  {
2232  struct_typet struct_type=
2233  static_cast<const struct_typet &>(
2234  cpp_typecheck.lookup(id.class_identifier).type);
2235  const exprt pcomp=struct_type.get_component(identifier);
2236  assert(pcomp.is_not_nil());
2237  assert(pcomp.get_bool(ID_is_type));
2238  const typet &type=pcomp.type();
2239  assert(type.id()!=ID_struct);
2240  if(type.id()==ID_symbol)
2241  identifier=type.get(ID_identifier);
2242  else
2243  continue;
2244  }
2245 
2246  while(true)
2247  {
2248  const symbolt &symbol=cpp_typecheck.lookup(identifier);
2249  assert(symbol.is_type);
2250 
2251  // todo? maybe do enum here, too?
2252  if(symbol.type.id()==ID_struct)
2253  {
2254  // this is a scope, too!
2255  cpp_idt &class_id=
2256  cpp_typecheck.cpp_scopes.get_id(identifier);
2257 
2258  assert(class_id.is_scope);
2259  new_set.insert(&class_id);
2260  break;
2261  }
2262  else if(symbol.type.id()==ID_symbol)
2263  identifier=symbol.type.get(ID_identifier);
2264  else
2265  break;
2266  }
2267  }
2269  {
2270  // std::cout << "X3\n";
2271  #if 0
2272  const symbolt &symbol=
2273  cpp_typecheck.lookup(id.identifier);
2274 
2275  // Template struct? Really needs arguments to be a scope!
2276  if(symbol.type.get(ID_type)==ID_struct)
2277  {
2278  id.print(std::cout);
2279  assert(id.is_scope);
2280  new_set.insert(&id);
2281  }
2282  #endif
2283  }
2285  {
2286  // std::cout << "X4\n";
2287  // a template parameter may evaluate to be a scope: it could
2288  // be instantiated with a class/struct/union/enum
2289  exprt e=cpp_typecheck.template_map.lookup(id.identifier);
2290 
2291  #if 0
2292  cpp_typecheck.template_map.print(std::cout);
2293  std::cout << "S: " << cpp_typecheck.cpp_scopes.current_scope().identifier
2294  << '\n';
2295  std::cout << "P: "
2297  << '\n';
2298  std::cout << "I: " << id.identifier << '\n';
2299  std::cout << "E: " << e.pretty() << '\n';
2300  #endif
2301 
2302  if(e.id()!=ID_type)
2303  continue; // expressions are definitively not a scope
2304 
2305  if(e.type().id()==ID_symbol)
2306  {
2307  symbol_typet type=to_symbol_type(e.type());
2308 
2309  while(true)
2310  {
2311  irep_idt identifier=type.get_identifier();
2312 
2313  const symbolt &symbol=cpp_typecheck.lookup(identifier);
2314  assert(symbol.is_type);
2315 
2316  if(symbol.type.id()==ID_symbol)
2317  type=to_symbol_type(symbol.type);
2318  else if(symbol.type.id()==ID_struct ||
2319  symbol.type.id()==ID_incomplete_struct ||
2320  symbol.type.id()==ID_union ||
2321  symbol.type.id()==ID_incomplete_union ||
2322  symbol.type.id()==ID_c_enum)
2323  {
2324  // this is a scope, too!
2325  cpp_idt &class_id=
2326  cpp_typecheck.cpp_scopes.get_id(identifier);
2327 
2328  assert(class_id.is_scope);
2329  new_set.insert(&class_id);
2330  break;
2331  }
2332  else // give up
2333  break;
2334  }
2335  }
2336  }
2337  }
2338 
2339  id_set.swap(new_set);
2340 }
2341 
2343  cpp_scopest::id_sett &id_set)
2344 {
2345  // we only want namespaces
2346  for(cpp_scopest::id_sett::iterator
2347  it=id_set.begin();
2348  it!=id_set.end();
2349  ) // no it++
2350  {
2351  if((*it)->is_namespace())
2352  it++;
2353  else
2354  {
2355  cpp_scopest::id_sett::iterator old(it);
2356  it++;
2357  id_set.erase(old);
2358  }
2359  }
2360 }
2361 
2363  cpp_scopest::id_sett &id_set,
2364  const irep_idt &base_name,
2365  const cpp_typecheck_fargst &fargs)
2366 {
2367  // not clear what this is good for
2368  for(const auto &arg : fargs.operands)
2369  {
2370  const typet &final_type=cpp_typecheck.follow(arg.type());
2371 
2372  if(final_type.id()!=ID_struct && final_type.id()!=ID_union)
2373  continue;
2374 
2375  cpp_scopest::id_sett tmp_set;
2376  cpp_scopet &scope=
2377  cpp_typecheck.cpp_scopes.get_scope(final_type.get(ID_name));
2378  scope.lookup(base_name, cpp_scopet::SCOPE_ONLY, tmp_set);
2379  id_set.insert(tmp_set.begin(), tmp_set.end());
2380  }
2381 }
const irep_idt & get_name() const
Definition: std_types.h:179
exprt convert_template_parameter(const cpp_idt &id)
The type of an expression.
Definition: type.h:20
mstreamt & warning()
Definition: message.h:228
irep_idt name
The unique identifier.
Definition: symbol.h:46
const typet & follow(const typet &src) const
Definition: namespace.cpp:66
virtual bool lookup(const irep_idt &name, const symbolt *&symbol) const
Definition: namespace.cpp:139
C++ Language Type Checking.
BigInt mp_integer
Definition: mp_arith.h:19
source_locationt source_location
void typecheck_type(typet &type)
Base type of functions.
Definition: std_types.h:734
bool is_nil() const
Definition: irep.h:103
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
bool is_not_nil() const
Definition: irep.h:104
bool match(const code_typet &code_type, unsigned &distance, cpp_typecheckt &cpp_typecheck) const
std::set< cpp_idt * > id_sett
Definition: cpp_scopes.h:31
void typecheck_expr_member(exprt &expr)
void lookup(const irep_idt &base_name, lookup_kindt kind, id_sett &id_set)
Definition: cpp_scope.cpp:29
const std::string integer2string(const mp_integer &n, unsigned base)
Definition: mp_arith.cpp:104
bool is_member
Definition: cpp_id.h:48
void print(std::ostream &out, unsigned indent=0) const
Definition: cpp_id.cpp:31
exprt & op0()
Definition: expr.h:84
void set_value(const irep_idt &value)
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:641
std::vector< irept > subt
Definition: irep.h:91
expr_mapt expr_map
Definition: template_map.h:30
exprt resolve(const cpp_namet &cpp_name, const wantt want, const cpp_typecheck_fargst &fargs, bool fail_with_exception=true)
instantiation_stackt instantiation_stack
exprt::operandst argumentst
irep_idt get_specialization_of() const
void guess_template_args(const typet &template_parameter, const typet &desired_type)
bool has_ellipsis() const
Definition: std_types.h:803
const symbolt & instantiate_template(const source_locationt &source_location, const symbolt &symbol, const cpp_template_args_tct &specialization_template_args, const cpp_template_args_tct &full_template_args, const typet &specialization=typet(ID_nil))
void clear()
Definition: symbol.h:79
void remove_duplicates(resolve_identifierst &identifiers)
void disambiguate_functions(resolve_identifierst &identifiers, const cpp_typecheck_fargst &fargs)
const irep_idt & get_function() const
cpp_template_args_tct typecheck_template_args(const source_locationt &source_location, const symbolt &template_symbol, const cpp_template_args_non_tct &template_args)
exprt::operandst operands
void copy_to_operands(const exprt &expr)
Definition: expr.cpp:61
void remove_templates(resolve_identifierst &identifiers)
const irep_idt & get_identifier() const
Definition: std_expr.h:120
void go_to(cpp_idt &id)
Definition: cpp_scopes.h:104
cpp_namet & to_cpp_name(irept &cpp_name)
Definition: cpp_name.h:143
std::vector< componentt > componentst
Definition: std_types.h:240
bool is_constructor
Definition: cpp_id.h:48
void move_to_operands(exprt &expr)
Definition: expr.cpp:28
subtypest & subtypes()
Definition: type.h:56
cpp_scopet & get_parent() const
Definition: cpp_scope.h:89
literalt pos(literalt a)
Definition: literal.h:193
std::vector< parametert > parameterst
Definition: std_types.h:829
An expression denoting a type.
Definition: std_expr.h:3671
cpp_template_args_non_tct & partial_specialization_args()
exprt convert_identifier(const cpp_idt &id, const wantt want, const cpp_typecheck_fargst &fargs)
void show_instantiation_stack(std::ostream &)
exprt value
Initial value of symbol.
Definition: symbol.h:40
const componentst & components() const
Definition: std_types.h:242
bool is_static_member
Definition: cpp_id.h:48
template_mapt template_map
bool has_component_rec(const typet &type, const irep_idt &component_name, const namespacet &ns)
cpp_template_args_tct & to_cpp_template_args_tc(irept &irep)
typet & type()
Definition: expr.h:60
bool cpp_typecheck(cpp_parse_treet &cpp_parse_tree, symbol_tablet &symbol_table, const std::string &module, message_handlert &message_handler)
unsignedbv_typet size_type()
Definition: c_types.cpp:57
Symbol table entry.This is a symbol in the symbol table, stored in an object of type symbol_tablet...
Definition: symbol.h:33
static mstreamt & eom(mstreamt &m)
Definition: message.h:193
Structure type.
Definition: std_types.h:296
bool get_bool(const irep_namet &name) const
Definition: irep.cpp:240
void go_to_root_scope()
Definition: cpp_scopes.h:99
cpp_template_args_non_tct & to_cpp_template_args_non_tc(irept &irep)
bool is_qualified() const
Definition: cpp_name.h:108
signedbv_typet signed_size_type()
Definition: c_types.cpp:73
exprt lookup(const irep_idt &identifier) const
cpp_scopet & get_root_scope()
Definition: cpp_scopes.h:94
subt & get_sub()
Definition: irep.h:245
Extract member of struct or union.
Definition: std_expr.h:3214
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a generic typet to a struct_union_typet.
Definition: std_types.h:277
bool is_class_template() const
std::string prefix
Definition: cpp_id.h:80
const irep_idt & id() const
Definition: irep.h:189
const source_locationt & source_location() const
Definition: cpp_name.h:72
const array_typet & to_array_type(const typet &type)
Cast a generic typet to an array_typet.
Definition: std_types.h:946
void elaborate_class_template(const typet &type)
elaborate class template instances
bool is_scope
Definition: cpp_id.h:48
const declaratorst & declarators() const
const symbol_typet & to_symbol_type(const typet &type)
Cast a generic typet to a symbol_typet.
Definition: std_types.h:142
void exact_match_functions(resolve_identifierst &identifiers, const cpp_typecheck_fargst &fargs)
A reference into the symbol table.
Definition: std_types.h:109
void filter_for_namespaces(cpp_scopest::id_sett &id_set)
The NIL expression.
Definition: std_expr.h:3764
type_mapt type_map
Definition: template_map.h:29
const source_locationt & find_source_location() const
Definition: expr.cpp:466
C++ Language Module.
bool has_template_args() const
Definition: cpp_name.h:121
source_locationt source_location
Definition: message.h:175
bool cpp_is_pod(const typet &type) const
Definition: cpp_is_pod.cpp:14
irep_idt identifier
Definition: cpp_id.h:73
C++ Language Conversion.
symbol_typet disambiguate_template_classes(const irep_idt &base_name, const cpp_scopest::id_sett &id_set, const cpp_template_args_non_tct &template_args)
disambiguate partial specialization
id_classt id_class
Definition: cpp_id.h:51
API to expression classes.
void filter(resolve_identifierst &identifiers, const wantt want)
bool is_reference(const typet &type)
TO_BE_DOCUMENTED.
Definition: std_types.cpp:105
cpp_idt & get_id(const irep_idt &identifier)
Definition: cpp_scopes.h:73
const irep_idt & get(const irep_namet &name) const
Definition: irep.cpp:213
cpp_template_args_tct build_template_args(const template_typet &template_type) const
std::string cpp_type2name(const typet &type)
Base class for tree-like data structures with sharing.
Definition: irep.h:87
irep_idt class_identifier
Definition: cpp_id.h:76
void add_object(const exprt &expr)
C++ Language Type Checking.
size_t size() const
Definition: dstring.h:77
id_mapt id_map
Definition: cpp_scopes.h:69
bool has_prefix(const std::string &s, const std::string &prefix)
Definition: converter.cpp:13
const struct_typet & to_struct_type(const typet &type)
Cast a generic typet to a struct_typet.
Definition: std_types.h:317
exprt this_expr
Definition: cpp_id.h:77
exprt do_builtin(const irep_idt &base_name, const cpp_template_args_non_tct &template_args)
typet type
Type of symbol.
Definition: symbol.h:37
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:43
cpp_declarationt & to_cpp_declaration(irept &irep)
void follow_symbol(irept &irep) const
Definition: namespace.cpp:43
API to type classes.
void guess_function_template_args(resolve_identifierst &identifiers, const cpp_typecheck_fargst &fargs)
guess arguments of function templates
bool subtype_typecast(const struct_typet &from, const struct_typet &to) const
void resolve_with_arguments(cpp_scopest::id_sett &id_set, const irep_idt &base_name, const cpp_typecheck_fargst &fargs)
void convert_identifiers(const cpp_scopest::id_sett &id_set, const wantt want, const cpp_typecheck_fargst &fargs, resolve_identifierst &identifiers)
cpp_template_args_tct specialization_args
Base type of C structs and unions, and C++ classes.
Definition: std_types.h:159
bool is_number(const typet &type)
Definition: type.cpp:24
const symbolt & class_template_symbol(const source_locationt &source_location, const symbolt &template_symbol, const cpp_template_args_tct &specialization_template_args, const cpp_template_args_tct &full_template_args)
Base class for all expressions.
Definition: expr.h:46
bool is_rvalue_reference(const typet &type)
TO_BE_DOCUMENTED.
Definition: std_types.cpp:111
const parameterst & parameters() const
Definition: std_types.h:841
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast a generic exprt to a symbol_exprt.
Definition: std_expr.h:202
cpp_scopet & current_scope()
Definition: cpp_scopes.h:33
void build_unassigned(const template_typet &template_type)
source_locationt & add_source_location()
Definition: type.h:100
const source_locationt & source_location() const
Definition: expr.h:142
bool is_method
Definition: cpp_id.h:48
virtual std::string to_string(const typet &type)
void cpp_convert_plain_type(typet &type)
const code_typet & to_code_type(const typet &type)
Cast a generic typet to a code_typet.
Definition: std_types.h:884
void make_nil()
Definition: irep.h:243
bool disable_access_control
void swap(irept &irep)
Definition: irep.h:231
void show_identifiers(const irep_idt &base_name, const resolve_identifierst &identifiers, std::ostream &out)
mstreamt & error()
Definition: message.h:223
source_locationt & add_source_location()
Definition: expr.h:147
cpp_typecheck_resolvet(class cpp_typecheckt &_cpp_typecheck)
Expression to hold a symbol (variable)
Definition: std_expr.h:82
cpp_scopet & get_scope(const irep_idt &identifier)
Definition: cpp_scopes.h:81
const char * c_str() const
Definition: dstring.h:72
std::vector< exprt > resolve_identifierst
bool to_integer(const exprt &expr, mp_integer &int_value)
Definition: arith_tools.cpp:18
Definition: cpp_id.h:28
signedbv_typet signed_int_type()
Definition: c_types.cpp:29
exprt cpp_symbol_expr(const symbolt &symbol)
Definition: cpp_util.cpp:14
void remove(const irep_namet &name)
Definition: irep.cpp:270
bool is_type
Definition: symbol.h:66
void make_constructors(resolve_identifierst &identifiers)
const typet & subtype() const
Definition: type.h:31
void filter_for_named_scopes(cpp_scopest::id_sett &id_set)
void apply_template_args(resolve_identifierst &identifiers, const cpp_template_args_non_tct &template_args, const cpp_typecheck_fargst &fargs)
template_typet & template_type()
bool is_root_scope() const
Definition: cpp_scope.h:73
bool empty() const
Definition: dstring.h:61
void make_typecast(const typet &_type)
Definition: expr.cpp:90
const irept & find(const irep_namet &name) const
Definition: irep.cpp:285
An enum tag type.
Definition: std_types.h:698
const typet & return_type() const
Definition: std_types.h:831
bool is_macro
Definition: symbol.h:66
const irep_idt & get_identifier() const
Definition: std_types.h:126
cpp_scopet & resolve_namespace(const cpp_namet &cpp_name)
void set(const irep_namet &name, const irep_idt &value)
Definition: irep.h:214
const componentt & get_component(const irep_idt &component_name) const
Definition: std_types.cpp:51
void print(std::ostream &out) const
cpp_typecheckt & cpp_typecheck
cpp_scopet & resolve_scope(const cpp_namet &cpp_name, irep_idt &base_name, cpp_template_args_non_tct &template_args)
C Language Type Checking.
cpp_scopest cpp_scopes