CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
linking_diagnostics.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: ANSI-C Linking
4
5Author: Michael Tautschnig
6
7\*******************************************************************/
8
11
12#include "linking_diagnostics.h"
13
14#include <util/c_types.h>
16#include <util/message.h>
17#include <util/namespace.h>
18
20
21#include <unordered_set>
22
23static const typet &follow_tags_symbols(const namespacet &ns, const typet &type)
24{
25 if(type.id() == ID_c_enum_tag)
26 return ns.follow_tag(to_c_enum_tag_type(type));
27 else if(type.id() == ID_struct_tag)
28 return ns.follow_tag(to_struct_tag_type(type));
29 else if(type.id() == ID_union_tag)
30 return ns.follow_tag(to_union_tag_type(type));
31 else
32 return type;
33}
34
36 const symbolt &symbol,
37 const typet &type) const
38{
39 const typet &followed = follow_tags_symbols(ns, type);
40
41 if(followed.id() == ID_struct || followed.id() == ID_union)
42 {
43 std::string result = followed.id_string();
44
45 const std::string &tag = followed.get_string(ID_tag);
46 if(!tag.empty())
47 result += " " + tag;
48
49 if(to_struct_union_type(followed).is_incomplete())
50 {
51 result += " (incomplete)";
52 }
53 else
54 {
55 result += " {\n";
56
57 for(const auto &c : to_struct_union_type(followed).components())
58 {
59 const typet &subtype = c.type();
60 result += " ";
61 result += from_type(ns, symbol.name, subtype);
62 result += ' ';
63
64 if(!c.get_base_name().empty())
65 result += id2string(c.get_base_name());
66 else
67 result += id2string(c.get_name());
68
69 result += ";\n";
70 }
71
72 result += '}';
73 }
74
75 return result;
76 }
77 else if(followed.id() == ID_pointer)
78 {
80 symbol, to_pointer_type(followed).base_type()) +
81 " *";
82 }
83
84 return from_type(ns, symbol.name, type);
85}
86
88 const symbolt &old_symbol,
89 const symbolt &new_symbol,
90 const typet &type1,
91 const typet &type2,
92 unsigned depth,
94{
95 bool conclusive = false;
96
97#ifdef DEBUG
99 log.debug() << "<BEGIN DEPTH " << depth << ">" << messaget::eom;
100#endif
101
102 std::string msg;
103
106
107 if(t1.id() != t2.id())
108 {
109 msg = "type classes differ";
110 conclusive = true;
111 }
112 else if(t1.id() == ID_pointer || t1.id() == ID_array)
113 {
114 if(
115 depth > 0 &&
116 to_type_with_subtype(t1).subtype() != to_type_with_subtype(t2).subtype())
117 {
118 if(conflict_path.type().id() == ID_pointer)
120
122 old_symbol,
123 new_symbol,
124 to_type_with_subtype(t1).subtype(),
125 to_type_with_subtype(t2).subtype(),
126 depth - 1,
128 }
129 else if(t1.id() == ID_pointer)
130 msg = "pointer types differ";
131 else
132 msg = "array types differ";
133 }
134 else if(t1.id() == ID_struct || t1.id() == ID_union)
135 {
137 to_struct_union_type(t1).components();
138
140 to_struct_union_type(t2).components();
141
143
144 if(components1.size() != components2.size())
145 {
146 msg = "number of members is different (";
147 msg += std::to_string(components1.size()) + '/';
148 msg += std::to_string(components2.size()) + ')';
149 conclusive = true;
150 }
151 else
152 {
153 for(std::size_t i = 0; i < components1.size(); ++i)
154 {
155 const typet &subtype1 = components1[i].type();
156 const typet &subtype2 = components2[i].type();
157
158 if(components1[i].get_name() != components2[i].get_name())
159 {
160 msg = "names of member " + std::to_string(i) + " differ (";
161 msg += id2string(components1[i].get_name()) + '/';
162 msg += id2string(components2[i].get_name()) + ')';
163 conclusive = true;
164 }
165 else if(subtype1 != subtype2)
166 {
167 typedef std::unordered_set<typet, irep_hash> type_sett;
169
171 while(e.id() == ID_dereference || e.id() == ID_member ||
172 e.id() == ID_index)
173 {
174 parent_types.insert(e.type());
176 if(e.id() == ID_dereference)
177 e = to_dereference_expr(e).pointer();
178 else if(e.id() == ID_member)
179 e = to_member_expr(e).compound();
180 else if(e.id() == ID_index)
181 e = to_index_expr(e).array();
182 else
184 }
185
186 if(parent_types.find(subtype1) == parent_types.end())
187 {
189 conflict_path.type() = t1;
191
192 if(depth > 0)
193 {
195 old_symbol,
196 new_symbol,
197 subtype1,
198 subtype2,
199 depth - 1,
201 }
202 }
203 else
204 {
205 msg = "type of member " + id2string(components1[i].get_name()) +
206 " differs (recursive)";
207 }
208 }
209
210 if(conclusive)
211 break;
212 }
213 }
214 }
215 else if(t1.id() == ID_c_enum)
216 {
218
220
221 if(
222 to_c_enum_type(t1).underlying_type() !=
223 to_c_enum_type(t2).underlying_type())
224 {
225 msg = "enum value types are different (";
226 msg +=
227 from_type(ns, old_symbol.name, to_c_enum_type(t1).underlying_type()) +
228 '/';
229 msg +=
230 from_type(ns, new_symbol.name, to_c_enum_type(t2).underlying_type()) +
231 ')';
232 conclusive = true;
233 }
234 else if(members1.size() != members2.size())
235 {
236 msg = "number of enum members is different (";
237 msg += std::to_string(members1.size()) + '/';
238 msg += std::to_string(members2.size()) + ')';
239 conclusive = true;
240 }
241 else
242 {
243 for(std::size_t i = 0; i < members1.size(); ++i)
244 {
246 {
247 msg = "names of member " + std::to_string(i) + " differ (";
248 msg += id2string(members1[i].get_base_name()) + '/';
249 msg += id2string(members2[i].get_base_name()) + ')';
250 conclusive = true;
251 }
252 else if(members1[i].get_value() != members2[i].get_value())
253 {
254 msg = "values of member " + std::to_string(i) + " differ (";
255 msg += id2string(members1[i].get_value()) + '/';
256 msg += id2string(members2[i].get_value()) + ')';
257 conclusive = true;
258 }
259
260 if(conclusive)
261 break;
262 }
263 }
264
265 msg += "\nenum declarations at\n";
266 msg += t1.source_location().as_string() + " and\n";
267 msg += t1.source_location().as_string();
268 }
269 else if(t1.id() == ID_code)
270 {
271 const code_typet::parameterst &parameters1 = to_code_type(t1).parameters();
272
273 const code_typet::parameterst &parameters2 = to_code_type(t2).parameters();
274
275 const typet &return_type1 = to_code_type(t1).return_type();
276 const typet &return_type2 = to_code_type(t2).return_type();
277
278 if(parameters1.size() != parameters2.size())
279 {
280 msg = "parameter counts differ (";
281 msg += std::to_string(parameters1.size()) + '/';
282 msg += std::to_string(parameters2.size()) + ')';
283 conclusive = true;
284 }
285 else if(return_type1 != return_type2)
286 {
289 conflict_path, constant_exprt(std::to_string(-1), integer_typet()));
290
291 if(depth > 0)
292 {
294 old_symbol,
295 new_symbol,
298 depth - 1,
300 }
301 else
302 msg = "return types differ";
303 }
304 else
305 {
306 for(std::size_t i = 0; i < parameters1.size(); i++)
307 {
308 const typet &subtype1 = parameters1[i].type();
309 const typet &subtype2 = parameters2[i].type();
310
311 if(subtype1 != subtype2)
312 {
315 conflict_path, constant_exprt(std::to_string(i), integer_typet()));
316
317 if(depth > 0)
318 {
320 old_symbol,
321 new_symbol,
322 subtype1,
323 subtype2,
324 depth - 1,
326 }
327 else
328 msg = "parameter types differ";
329 }
330
331 if(conclusive)
332 break;
333 }
334 }
335 }
336 else
337 {
338 msg = "conflict on POD";
339 conclusive = true;
340 }
341
342 if(conclusive && !msg.empty())
343 {
344#ifndef DEBUG
346#endif
347 log.error() << '\n';
348 log.error() << "reason for conflict at "
349 << from_expr(ns, irep_idt(), conflict_path) << ": " << msg
350 << '\n';
351
352 log.error() << '\n';
353 log.error() << type_to_string_verbose(old_symbol, t1) << '\n';
354 log.error() << type_to_string_verbose(new_symbol, t2) << '\n'
355 << messaget::eom;
356 }
357
358#ifdef DEBUG
359 log.debug() << "<END DEPTH " << depth << ">" << messaget::eom;
360#endif
361
362 return conclusive;
363}
364
366 const symbolt &old_symbol,
367 const symbolt &new_symbol,
368 const std::string &msg)
369{
371 log.error().source_location = new_symbol.location;
372
373 log.error() << msg << " '" << old_symbol.display_name() << "'" << '\n';
374 log.error() << "old definition in module '" << old_symbol.module << "' "
375 << old_symbol.location << '\n'
376 << type_to_string_verbose(old_symbol) << '\n';
377 log.error() << "new definition in module '" << new_symbol.module << "' "
378 << new_symbol.location << '\n'
379 << type_to_string_verbose(new_symbol) << messaget::eom;
380}
381
383 const symbolt &old_symbol,
384 const symbolt &new_symbol,
385 const std::string &msg)
386{
388 log.warning().source_location = new_symbol.location;
389
390 log.warning() << msg << " '" << old_symbol.display_name() << "'\n";
391 log.warning() << "old definition in module " << old_symbol.module << " "
392 << old_symbol.location << '\n'
393 << type_to_string_verbose(old_symbol) << '\n';
394 log.warning() << "new definition in module " << new_symbol.module << " "
395 << new_symbol.location << '\n'
396 << type_to_string_verbose(new_symbol) << messaget::eom;
397}
empty_typet void_type()
Definition c_types.cpp:245
const c_enum_typet & to_c_enum_type(const typet &type)
Cast a typet to a c_enum_typet.
Definition c_types.h:335
const c_enum_tag_typet & to_c_enum_tag_type(const typet &type)
Cast a typet to a c_enum_tag_typet.
Definition c_types.h:377
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition c_types.h:224
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Arrays with given size.
Definition std_types.h:807
std::vector< c_enum_membert > memberst
Definition c_types.h:275
std::vector< parametert > parameterst
Definition std_types.h:586
A constant literal expression.
Definition std_expr.h:3117
Operator to dereference a pointer.
Base class for all expressions.
Definition expr.h:56
typet & type()
Return the type of the expression.
Definition expr.h:84
Array index operator.
Definition std_expr.h:1470
Unbounded, signed integers (mathematical integers, not bitvectors)
const irep_idt & id() const
Definition irep.h:388
message_handlert & message_handler
const namespacet & ns
std::string type_to_string_verbose(const symbolt &symbol, const typet &type) const
void warning(const symbolt &old_symbol, const symbolt &new_symbol, const std::string &msg)
bool detailed_conflict_report_rec(const symbolt &old_symbol, const symbolt &new_symbol, const typet &type1, const typet &type2, unsigned depth, exprt &conflict_path)
Returns true iff the conflict report on a particular branch of the tree of types was a definitive res...
void error(const symbolt &old_symbol, const symbolt &new_symbol, const std::string &msg)
Extract member of struct or union.
Definition std_expr.h:2971
Class that provides messages with a built-in verbosity 'level'.
Definition message.h:154
static eomt eom
Definition message.h:289
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition namespace.cpp:49
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
The NIL expression.
Definition std_expr.h:3208
std::vector< componentt > componentst
Definition std_types.h:140
Symbol table entry.
Definition symbol.h:28
source_locationt location
Source code location of definition of symbol.
Definition symbol.h:37
irep_idt name
The unique identifier.
Definition symbol.h:40
const irep_idt & display_name() const
Return language specific display name if present.
Definition symbol.h:55
The type of an expression, extends irept.
Definition type.h:29
std::string get_base_name(const std::string &in, bool strip_suffix)
cleans a filename from path and extension
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
std::string from_type(const namespacet &ns, const irep_idt &identifier, const typet &type)
static const typet & follow_tags_symbols(const namespacet &ns, const typet &type)
Definition linking.cpp:28
static const typet & follow_tags_symbols(const namespacet &ns, const typet &type)
ANSI-C Linking.
double log(double x)
Definition math.c:2449
Mathematical types.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3063
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:788
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:518
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition std_types.h:214
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition type.h:208
dstringt irep_idt