cprover
cpp_typecheck_bases.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.h"
13 
14 #include <set>
15 
17 {
18  std::set<irep_idt> bases;
19  std::set<irep_idt> vbases;
20 
21  irep_idt default_class_access = type.default_access();
22 
23  irept::subt &bases_irep=type.add(ID_bases).get_sub();
24 
25  Forall_irep(base_it, bases_irep)
26  {
27  const cpp_namet &name=
28  to_cpp_name(base_it->find(ID_name));
29 
30  exprt base_symbol_expr=
31  resolve(
32  name,
35 
36  if(base_symbol_expr.id()!=ID_type)
37  {
39  error() << "expected type as struct/class base" << eom;
40  throw 0;
41  }
42 
43  // elaborate any class template instances given as bases
44  elaborate_class_template(base_symbol_expr.type());
45 
46  if(base_symbol_expr.type().id() == ID_symbol_type)
47  base_symbol_expr.type().id(ID_struct_tag);
48 
49  if(base_symbol_expr.type().id() != ID_struct_tag)
50  {
52  error() << "expected type symbol as struct/class base" << eom;
53  throw 0;
54  }
55 
56  const symbolt &base_symbol =
57  lookup(to_struct_tag_type(base_symbol_expr.type()));
58 
59  if(base_symbol.type.id()==ID_incomplete_struct)
60  {
62  error() << "base type is incomplete" << eom;
63  throw 0;
64  }
65  else if(base_symbol.type.id()!=ID_struct)
66  {
68  error() << "expected struct or class as base, but got `"
69  << to_string(base_symbol.type) << "'" << eom;
70  throw 0;
71  }
72 
73  bool virtual_base = base_it->get_bool(ID_virtual);
74  irep_idt class_access = base_it->get(ID_protection);
75 
76  if(class_access.empty())
77  class_access = default_class_access;
78 
79  base_symbol_expr.id(ID_base);
80  base_symbol_expr.set(ID_access, class_access);
81 
82  if(virtual_base)
83  base_symbol_expr.set(ID_virtual, true);
84 
85  base_it->swap(base_symbol_expr);
86 
87  // Add base scopes as parents to the current scope
89  static_cast<cpp_scopet &>(*cpp_scopes.id_map[base_symbol.name]));
90 
91  const struct_typet &base_struct_type=
92  to_struct_type(base_symbol.type);
93 
95  base_struct_type,
96  class_access,
97  type,
98  bases,
99  vbases,
100  virtual_base);
101  }
102 
103  if(!vbases.empty())
104  {
105  // add a flag to determine
106  // if this is the most-derived-object
107  struct_typet::componentt most_derived(
108  cpp_scopes.current_scope().prefix + "::" + "@most_derived", bool_typet());
109 
110  most_derived.set_access(ID_public);
111  most_derived.set_base_name("@most_derived");
112  most_derived.set_pretty_name("@most_derived");
113  most_derived.add_source_location()=type.source_location();
114  put_compound_into_scope(most_derived);
115 
116  to_struct_type(type).components().push_back(most_derived);
117  }
118 }
119 
121  const struct_typet &from,
122  const irep_idt &access,
123  struct_typet &to,
124  std::set<irep_idt> &bases,
125  std::set<irep_idt> &vbases,
126  bool is_virtual)
127 {
128  const irep_idt &from_name = from.get(ID_name);
129 
130  if(is_virtual && vbases.find(from_name)!=vbases.end())
131  return;
132 
133  if(bases.find(from_name)!=bases.end())
134  {
136  error() << "error: non-virtual base class " << from_name
137  << " inherited multiple times" << eom;
138  throw 0;
139  }
140 
141  bases.insert(from_name);
142 
143  if(is_virtual)
144  vbases.insert(from_name);
145 
146  // look at the the parents of the base type
147  for(const auto &b : from.bases())
148  {
149  irep_idt sub_access = b.get(ID_access);
150 
151  if(access==ID_private)
152  sub_access=ID_private;
153  else if(access==ID_protected && sub_access!=ID_private)
154  sub_access=ID_protected;
155 
156  const symbolt &symb = lookup(b.type());
157 
158  const bool is_virtual_base = b.get_bool(ID_virtual);
159 
160  // recursive call
162  to_struct_type(symb.type),
163  sub_access,
164  to,
165  bases,
166  vbases,
167  is_virtual_base);
168  }
169 
170  // add the components
172 
173  for(const auto &c : from.components())
174  {
175  if(c.get_bool(ID_from_base))
176  continue;
177 
178  // copy the component
179  dest_c.push_back(c);
180 
181  // now twiddle the copy
182  struct_typet::componentt &component=dest_c.back();
183  component.set(ID_from_base, true);
184 
185  irep_idt comp_access=component.get_access();
186 
187  if(access==ID_public)
188  {
189  if(comp_access==ID_private)
190  component.set_access(ID_noaccess);
191  }
192  else if(access == ID_protected)
193  {
194  if(comp_access==ID_private)
195  component.set_access(ID_noaccess);
196  else
197  component.set_access(ID_private);
198  }
199  else if(access == ID_private)
200  {
201  if(comp_access == ID_noaccess || comp_access == ID_private)
202  component.set_access(ID_noaccess);
203  else
204  component.set_access(ID_private);
205  }
206  else
207  UNREACHABLE;
208 
209  // put into scope
210  }
211 }
struct_union_typet::components
const componentst & components() const
Definition: std_types.h:205
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:35
cpp_scopet
Definition: cpp_scope.h:20
cpp_typecheckt::elaborate_class_template
void elaborate_class_template(const typet &type)
elaborate class template instances
Definition: cpp_instantiate_template.cpp:186
cpp_typecheckt::add_base_components
void add_base_components(const struct_typet &from, const irep_idt &access, struct_typet &to, std::set< irep_idt > &bases, std::set< irep_idt > &vbases, bool is_virtual)
Definition: cpp_typecheck_bases.cpp:120
cpp_typecheck_fargst
Definition: cpp_typecheck_fargs.h:22
to_struct_type
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:349
struct_union_typet::componentt::set_access
void set_access(const irep_idt &access)
Definition: std_types.h:157
cpp_scopest::id_map
id_mapt id_map
Definition: cpp_scopes.h:69
cpp_typecheckt::cpp_scopes
cpp_scopest cpp_scopes
Definition: cpp_typecheck.h:109
symbolt::type
typet type
Type of symbol.
Definition: symbol.h:31
irept::add
irept & add(const irep_namet &name)
Definition: irep.cpp:305
cpp_typecheckt::typecheck_compound_bases
void typecheck_compound_bases(struct_typet &type)
Definition: cpp_typecheck_bases.cpp:16
exprt
Base class for all expressions.
Definition: expr.h:54
struct_union_typet::componentst
std::vector< componentt > componentst
Definition: std_types.h:203
component
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition: std_expr.cpp:173
bool_typet
The Boolean type.
Definition: std_types.h:28
messaget::eom
static eomt eom
Definition: message.h:284
struct_union_typet::default_access
irep_idt default_access() const
Return the access specification for members where access has not been modified.
Definition: std_types.h:237
Forall_irep
#define Forall_irep(it, irep)
Definition: irep.h:66
UNREACHABLE
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:478
cpp_typecheck_resolvet::wantt::TYPE
@ TYPE
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:68
namespacet::lookup
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:166
messaget::error
mstreamt & error() const
Definition: message.h:386
cpp_scopet::add_secondary_scope
void add_secondary_scope(cpp_scopet &other)
Definition: cpp_scope.h:108
cpp_scopest::current_scope
cpp_scopet & current_scope()
Definition: cpp_scopes.h:33
messaget::mstreamt::source_location
source_locationt source_location
Definition: message.h:236
typet::source_location
const source_locationt & source_location() const
Definition: type.h:62
struct_union_typet::componentt::set_pretty_name
void set_pretty_name(const irep_idt &name)
Definition: std_types.h:167
struct_union_typet::componentt::set_base_name
void set_base_name(const irep_idt &base_name)
Definition: std_types.h:147
struct_typet::bases
const basest & bases() const
Get the collection of base classes/structs.
Definition: std_types.h:303
cpp_typecheckt::put_compound_into_scope
void put_compound_into_scope(const struct_union_typet::componentt &component)
Definition: cpp_typecheck_compound_type.cpp:778
irept::id
const irep_idt & id() const
Definition: irep.h:259
to_struct_tag_type
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:543
dstringt::empty
bool empty() const
Definition: dstring.h:75
cpp_typecheck.h
struct_union_typet::componentt
Definition: std_types.h:121
struct_typet
Structure type, corresponds to C style structs.
Definition: std_types.h:276
cpp_namet::source_location
const source_locationt & source_location() const
Definition: cpp_name.h:73
irept::get
const irep_idt & get(const irep_namet &name) const
Definition: irep.cpp:212
symbolt
Symbol table entry.
Definition: symbol.h:27
irept::set
void set(const irep_namet &name, const irep_idt &value)
Definition: irep.h:286
irept::get_sub
subt & get_sub()
Definition: irep.h:317
cpp_idt::prefix
std::string prefix
Definition: cpp_id.h:80
cpp_typecheckt::to_string
std::string to_string(const typet &) override
Definition: cpp_typecheck.cpp:84
exprt::add_source_location
source_locationt & add_source_location()
Definition: expr.h:233
cpp_typecheckt::resolve
exprt resolve(const cpp_namet &cpp_name, const cpp_typecheck_resolvet::wantt want, const cpp_typecheck_fargst &fargs, bool fail_with_exception=true)
Definition: cpp_typecheck.h:88
irept::subt
std::vector< irept > subt
Definition: irep.h:160
cpp_namet
Definition: cpp_name.h:16
symbolt::name
irep_idt name
The unique identifier.
Definition: symbol.h:40
to_cpp_name
cpp_namet & to_cpp_name(irept &cpp_name)
Definition: cpp_name.h:144