Skip to content

Commit bb2f51f

Browse files
author
kroening
committed
Added detailed type conflict reporting
git-svn-id: svn+ssh://svn.cprover.org/srv/svn/cbmc/trunk@6376 6afb6bc1-c8e4-404c-8f48-9ae832c5b171
1 parent 0308c7b commit bb2f51f

File tree

2 files changed

+228
-33
lines changed

2 files changed

+228
-33
lines changed

src/linking/linking.cpp

Lines changed: 203 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ std::string linkingt::type_to_string_verbose(
129129

130130
/*******************************************************************\
131131
132-
Function: linkingt::link_error
132+
Function: linkingt::detailed_conflict_report
133133
134134
Inputs:
135135
@@ -139,37 +139,192 @@ Function: linkingt::link_error
139139
140140
\*******************************************************************/
141141

142-
void linkingt::show_struct_diff(
143-
const struct_typet &old_type, const struct_typet &new_type)
142+
void linkingt::detailed_conflict_report_rec(
143+
const symbolt &old_symbol,
144+
const symbolt &new_symbol,
145+
const typet &type1,
146+
const typet &type2,
147+
unsigned depth,
148+
exprt &conflict_path)
144149
{
145-
if(old_type.components().size()!=new_type.components().size())
146-
str << "number of members is different";
147-
else
150+
#ifdef DEBUG
151+
str << "<BEGIN DEPTH " << depth << ">";
152+
debug();
153+
#endif
154+
155+
std::string msg;
156+
157+
const typet &t1=ns.follow(type1);
158+
const typet &t2=ns.follow(type2);
159+
160+
if(t1.id()!=t2.id())
161+
msg="type classes differ";
162+
else if(t1.id()==ID_pointer ||
163+
t1.id()==ID_array)
164+
{
165+
if(depth>0 &&
166+
!base_type_eq(t1.subtype(), t2.subtype(), ns))
167+
{
168+
conflict_path=dereference_exprt(conflict_path);
169+
170+
detailed_conflict_report_rec(
171+
old_symbol,
172+
new_symbol,
173+
t1.subtype(),
174+
t2.subtype(),
175+
depth-1,
176+
conflict_path);
177+
}
178+
else if(t1.id()==ID_pointer)
179+
msg="pointer types differ";
180+
else
181+
msg="array types differ";
182+
}
183+
else if(t1.id()==ID_struct ||
184+
t1.id()==ID_union)
148185
{
149-
for(unsigned i=0; i<old_type.components().size(); i++)
186+
const struct_union_typet::componentst &components1=
187+
to_struct_union_type(t1).components();
188+
189+
const struct_union_typet::componentst &components2=
190+
to_struct_union_type(t2).components();
191+
192+
if(components1.size()!=components2.size())
150193
{
151-
if(old_type.components()[i].get_name()!=new_type.components()[i].get_name())
194+
msg="number of members is different (";
195+
msg+=i2string(components1.size())+'/';
196+
msg+=i2string(components2.size())+')';
197+
}
198+
else
199+
for(std::size_t i=0; i<components1.size(); ++i)
152200
{
153-
str << "name of member differs: "
154-
<< old_type.components()[i].get_name() << " vs. "
155-
<< new_type.components()[i].get_name();
156-
break;
201+
const typet &subtype1=components1[i].type();
202+
const typet &subtype2=components2[i].type();
203+
204+
if(components1[i].get_name()!=components2[i].get_name())
205+
{
206+
msg="names of member "+i2string(i)+" differ (";
207+
msg+=id2string(components1[i].get_name())+'/';
208+
msg+=id2string(components2[i].get_name())+')';
209+
break;
210+
}
211+
else if(!base_type_eq(subtype1, subtype2, ns))
212+
{
213+
conflict_path.type()=t1;
214+
conflict_path=
215+
member_exprt(conflict_path, components1[i].get_name());
216+
217+
if(depth>0)
218+
detailed_conflict_report_rec(
219+
old_symbol,
220+
new_symbol,
221+
subtype1,
222+
subtype2,
223+
depth-1,
224+
conflict_path);
225+
else
226+
msg="type of member "+
227+
id2string(components1[i].get_name())+
228+
" differs";
229+
230+
break;
231+
}
157232
}
158-
159-
if(!base_type_eq(old_type.components()[i].type(), new_type.components()[i].type(), ns))
233+
}
234+
else if(t1.id()==ID_code)
235+
{
236+
const code_typet::parameterst &parameters1=
237+
to_code_type(t1).parameters();
238+
239+
const code_typet::parameterst &parameters2=
240+
to_code_type(t2).parameters();
241+
242+
const typet &return_type1=to_code_type(t1).return_type();
243+
const typet &return_type2=to_code_type(t2).return_type();
244+
245+
if(parameters1.size()!=parameters2.size())
246+
{
247+
msg="parameter counts differ (";
248+
msg+=i2string(parameters1.size())+'/';
249+
msg+=i2string(parameters2.size())+')';
250+
}
251+
else if(!base_type_eq(return_type1, return_type2, ns))
252+
{
253+
conflict_path=
254+
index_exprt(conflict_path,
255+
constant_exprt(i2string(-1), integer_typet()));
256+
257+
if(depth>0)
258+
detailed_conflict_report_rec(
259+
old_symbol,
260+
new_symbol,
261+
return_type1,
262+
return_type2,
263+
depth-1,
264+
conflict_path);
265+
else
266+
msg="return types differ";
267+
}
268+
else
269+
for(std::size_t i=0; i<parameters1.size(); i++)
160270
{
161-
str << "type of member "
162-
<< old_type.components()[i].get_name() << " differs: "
163-
<< type_to_string(ns, "", old_type.components()[i].type()) << " vs. "
164-
<< type_to_string(ns, "", new_type.components()[i].type());
165-
str << "\n" << old_type.components()[i].type().pretty() << "\n";
166-
str << "\n" << new_type.components()[i].type().pretty() << "\n";
167-
break;
271+
const typet &subtype1=parameters1[i].type();
272+
const typet &subtype2=parameters2[i].type();
273+
274+
if(!base_type_eq(subtype1, subtype2, ns))
275+
{
276+
conflict_path=
277+
index_exprt(conflict_path,
278+
constant_exprt(i2string(i), integer_typet()));
279+
280+
if(depth>0)
281+
detailed_conflict_report_rec(
282+
old_symbol,
283+
new_symbol,
284+
subtype1,
285+
subtype2,
286+
depth-1,
287+
conflict_path);
288+
else
289+
msg="parameter types differ";
290+
291+
break;
292+
}
168293
}
169-
}
170294
}
295+
else
296+
msg="conflict on POD";
297+
298+
if(!msg.empty())
299+
{
300+
str << std::endl;
301+
str << "reason for conflict at "
302+
<< expr_to_string(ns, "", conflict_path)
303+
<< ": " << msg << std::endl;
304+
305+
str << std::endl;
306+
str << type_to_string_verbose(ns, old_symbol, t1) << std::endl;
307+
str << type_to_string_verbose(ns, new_symbol, t2) << std::endl;
308+
}
309+
310+
#ifdef DEBUG
311+
str << "<END DEPTH " << depth << ">";
312+
debug();
313+
#endif
171314
}
172315

316+
/*******************************************************************\
317+
318+
Function: linkingt::link_error
319+
320+
Inputs:
321+
322+
Outputs:
323+
324+
Purpose:
325+
326+
\*******************************************************************/
327+
173328
void linkingt::link_error(
174329
const symbolt &old_symbol,
175330
const symbolt &new_symbol,
@@ -187,15 +342,6 @@ void linkingt::link_error(
187342
<< "' " << new_symbol.location << "\n"
188343
<< type_to_string_verbose(ns, new_symbol);
189344

190-
if(ns.follow(old_symbol.type).id()==ID_struct &&
191-
ns.follow(new_symbol.type).id()==ID_struct)
192-
{
193-
str << "\n";
194-
str << "Difference between struct types:\n";
195-
show_struct_diff(to_struct_type(ns.follow(old_symbol.type)),
196-
to_struct_type(ns.follow(new_symbol.type)));
197-
}
198-
199345
throw 0;
200346
}
201347

@@ -224,7 +370,7 @@ void linkingt::link_warning(
224370
<< type_to_string_verbose(ns, old_symbol) << std::endl;
225371
str << "new definition in module " << new_symbol.module
226372
<< " " << new_symbol.location << std::endl
227-
<< type_to_string_verbose(ns, new_symbol);
373+
<< type_to_string_verbose(ns, new_symbol) << std::endl;
228374

229375
warning_msg();
230376
}
@@ -457,10 +603,18 @@ void linkingt::duplicate_code_symbol(
457603
}
458604

459605
if(!conflicts.empty())
606+
{
607+
detailed_conflict_report(
608+
old_symbol,
609+
new_symbol,
610+
conflicts.front().first,
611+
conflicts.front().second);
612+
460613
link_error(
461614
old_symbol,
462615
new_symbol,
463616
"conflicting function declarations");
617+
}
464618
else
465619
{
466620
// warns about the first inconsistency
@@ -494,7 +648,7 @@ void linkingt::duplicate_code_symbol(
494648
// keep the one in old_symbol -- libraries come last!
495649
str << "warning: function `" << old_symbol.name << "' in module `" <<
496650
new_symbol.module << "' is shadowed by a definition in module `" <<
497-
old_symbol.module << "'";
651+
old_symbol.module << "'" << std::endl;
498652
warning_msg();
499653
}
500654
else
@@ -582,6 +736,16 @@ void linkingt::duplicate_object_symbol(
582736
}
583737
else
584738
{
739+
// provide additional diagnostic output for struct/union/array
740+
if(old_type.id()==ID_struct ||
741+
old_type.id()==ID_union ||
742+
old_type.id()==ID_array)
743+
detailed_conflict_report(
744+
old_symbol,
745+
new_symbol,
746+
old_symbol.type,
747+
new_symbol.type);
748+
585749
link_error(
586750
old_symbol,
587751
new_symbol,
@@ -749,6 +913,12 @@ void linkingt::duplicate_type_symbol(
749913
}
750914
}
751915

916+
detailed_conflict_report(
917+
old_symbol,
918+
new_symbol,
919+
old_symbol.type,
920+
new_symbol.type);
921+
752922
link_error(
753923
old_symbol,
754924
new_symbol,

src/linking/linking_class.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Daniel Kroening, [email protected]
1313
#include <util/rename_symbol.h>
1414
#include <util/hash_cont.h>
1515
#include <util/typecheck.h>
16+
#include <util/std_expr.h>
1617

1718
class linkingt:public typecheckt
1819
{
@@ -97,6 +98,30 @@ class linkingt:public typecheckt
9798
return type_to_string_verbose(ns, symbol, symbol.type);
9899
}
99100

101+
void detailed_conflict_report_rec(
102+
const symbolt &old_symbol,
103+
const symbolt &new_symbol,
104+
const typet &type1,
105+
const typet &type2,
106+
unsigned depth,
107+
exprt &conflict_path);
108+
109+
void detailed_conflict_report(
110+
const symbolt &old_symbol,
111+
const symbolt &new_symbol,
112+
const typet &type1,
113+
const typet &type2)
114+
{
115+
symbol_exprt conflict_path(ID_C_this);
116+
detailed_conflict_report_rec(
117+
old_symbol,
118+
new_symbol,
119+
type1,
120+
type2,
121+
10, // somewhat arbitrary limit
122+
conflict_path);
123+
}
124+
100125
void link_error(
101126
const symbolt &old_symbol,
102127
const symbolt &new_symbol,

0 commit comments

Comments
 (0)