Skip to content

Commit dceaf01

Browse files
committed
Improving linker warning diagnostics
We previously just reported pointer type conflicts without elaborating what the exact difference was. To produce type-consistent goto programs, we chose to use the type that the definition had, but lacked any test that doing so would actually result in a program that can be analysed successfully. This commit fixes bugs in the code producing diagnostics, enables diagnostics for the case of pointer type conflicts, and adds a test to demonstrate that we successfully analyse programs after type conflict resolution. Despite this, however, inconsistencies in the goto program remain: the call types still need fixing up. Fixes: diffblue#198
1 parent ec13391 commit dceaf01

File tree

7 files changed

+148
-43
lines changed

7 files changed

+148
-43
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
typesmain.c
3+
types1.c types2.c types3.c --verbosity 2
4+
reason for conflict at \*#this.u: number of members is different \(3/0\)
5+
reason for conflict at \*#this.u: number of members is different \(0/3\)
6+
struct U \(incomplete\)
7+
warning: pointer parameter types differ between declaration and definition "bar"
8+
warning: pointer parameter types differ between declaration and definition "foo"
9+
^EXIT=0$
10+
^SIGNAL=0$
11+
--
12+
^warning: ignoring
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
struct S
2+
{
3+
int s;
4+
} s_object;
5+
6+
int foobar()
7+
{
8+
return s_object.s;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
struct S
2+
{
3+
struct T *t;
4+
struct U *u;
5+
};
6+
7+
struct U
8+
{
9+
struct S *s;
10+
int j;
11+
};
12+
13+
int bar(struct S *s)
14+
{
15+
return s->u->j;
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
struct T
2+
{
3+
int i;
4+
};
5+
6+
struct S
7+
{
8+
struct T *t;
9+
struct U *u;
10+
};
11+
12+
int bar(struct S *);
13+
14+
int foo(struct S *s)
15+
{
16+
return bar(s) + s->t->i;
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <assert.h>
2+
3+
struct T
4+
{
5+
int i;
6+
};
7+
8+
struct U
9+
{
10+
struct S *s;
11+
int j;
12+
};
13+
14+
struct S
15+
{
16+
struct T *t;
17+
struct U *u;
18+
};
19+
20+
int foo(struct S *s);
21+
22+
int main()
23+
{
24+
struct T t = {10};
25+
struct U u = {0, 32};
26+
struct S s = {&t, &u};
27+
int res = foo(&s);
28+
assert(res == 42);
29+
}

src/linking/linking.cpp

+61-42
Original file line numberDiff line numberDiff line change
@@ -127,25 +127,30 @@ std::string linkingt::type_to_string_verbose(
127127
return type_to_string(symbol.name, type);
128128
}
129129

130-
void linkingt::detailed_conflict_report_rec(
130+
bool linkingt::detailed_conflict_report_rec(
131131
const symbolt &old_symbol,
132132
const symbolt &new_symbol,
133133
const typet &type1,
134134
const typet &type2,
135135
unsigned depth,
136136
exprt &conflict_path)
137137
{
138-
#ifdef DEBUG
138+
bool conclusive = false;
139+
140+
#ifdef DEBUG
139141
debug() << "<BEGIN DEPTH " << depth << ">" << eom;
140-
#endif
142+
#endif
141143

142144
std::string msg;
143145

144146
const typet &t1=follow_tags_symbols(ns, type1);
145147
const typet &t2=follow_tags_symbols(ns, type2);
146148

147149
if(t1.id()!=t2.id())
150+
{
148151
msg="type classes differ";
152+
conclusive = true;
153+
}
149154
else if(t1.id()==ID_pointer ||
150155
t1.id()==ID_array)
151156
{
@@ -158,7 +163,7 @@ void linkingt::detailed_conflict_report_rec(
158163
if(conflict_path.type().id() == ID_pointer)
159164
conflict_path = dereference_exprt(conflict_path);
160165

161-
detailed_conflict_report_rec(
166+
conclusive = detailed_conflict_report_rec(
162167
old_symbol,
163168
new_symbol,
164169
to_type_with_subtype(t1).subtype(),
@@ -187,6 +192,7 @@ void linkingt::detailed_conflict_report_rec(
187192
msg="number of members is different (";
188193
msg+=std::to_string(components1.size())+'/';
189194
msg+=std::to_string(components2.size())+')';
195+
conclusive = true;
190196
}
191197
else
192198
{
@@ -200,7 +206,7 @@ void linkingt::detailed_conflict_report_rec(
200206
msg="names of member "+std::to_string(i)+" differ (";
201207
msg+=id2string(components1[i].get_name())+'/';
202208
msg+=id2string(components2[i].get_name())+')';
203-
break;
209+
conclusive = true;
204210
}
205211
else if(!base_type_eq(subtype1, subtype2, ns))
206212
{
@@ -213,6 +219,7 @@ void linkingt::detailed_conflict_report_rec(
213219
e.id()==ID_index)
214220
{
215221
parent_types.insert(e.type());
222+
parent_types.insert(follow_tags_symbols(ns, e.type()));
216223
if(e.id() == ID_dereference)
217224
e = to_dereference_expr(e).pointer();
218225
else if(e.id() == ID_member)
@@ -223,44 +230,32 @@ void linkingt::detailed_conflict_report_rec(
223230
UNREACHABLE;
224231
}
225232

226-
conflict_path=conflict_path_before;
227-
conflict_path.type()=t1;
228-
conflict_path=
229-
member_exprt(conflict_path, components1[i]);
230-
231-
if(depth>0 &&
232-
parent_types.find(t1)==parent_types.end())
233-
detailed_conflict_report_rec(
234-
old_symbol,
235-
new_symbol,
236-
subtype1,
237-
subtype2,
238-
depth-1,
239-
conflict_path);
240-
else
233+
if(parent_types.find(subtype1) == parent_types.end())
241234
{
242-
msg="type of member "+
243-
id2string(components1[i].get_name())+
244-
" differs";
245-
if(depth>0)
235+
conflict_path = conflict_path_before;
236+
conflict_path.type() = t1;
237+
conflict_path = member_exprt(conflict_path, components1[i]);
238+
239+
if(depth > 0)
246240
{
247-
std::string msg_bak;
248-
msg_bak.swap(msg);
249-
symbol_exprt c = symbol_exprt::typeless(ID_C_this);
250-
detailed_conflict_report_rec(
241+
conclusive = detailed_conflict_report_rec(
251242
old_symbol,
252243
new_symbol,
253244
subtype1,
254245
subtype2,
255-
depth-1,
256-
c);
257-
msg.swap(msg_bak);
246+
depth - 1,
247+
conflict_path);
258248
}
259249
}
260-
261-
if(parent_types.find(t1)==parent_types.end())
262-
break;
250+
else
251+
{
252+
msg = "type of member " + id2string(components1[i].get_name()) +
253+
" differs (recursive)";
254+
}
263255
}
256+
257+
if(conclusive)
258+
break;
264259
}
265260
}
266261
}
@@ -283,12 +278,14 @@ void linkingt::detailed_conflict_report_rec(
283278
msg +=
284279
type_to_string(new_symbol.name, to_c_enum_type(t2).underlying_type()) +
285280
')';
281+
conclusive = true;
286282
}
287283
else if(members1.size()!=members2.size())
288284
{
289285
msg="number of enum members is different (";
290286
msg+=std::to_string(members1.size())+'/';
291287
msg+=std::to_string(members2.size())+')';
288+
conclusive = true;
292289
}
293290
else
294291
{
@@ -299,15 +296,18 @@ void linkingt::detailed_conflict_report_rec(
299296
msg="names of member "+std::to_string(i)+" differ (";
300297
msg+=id2string(members1[i].get_base_name())+'/';
301298
msg+=id2string(members2[i].get_base_name())+')';
302-
break;
299+
conclusive = true;
303300
}
304301
else if(members1[i].get_value()!=members2[i].get_value())
305302
{
306303
msg="values of member "+std::to_string(i)+" differ (";
307304
msg+=id2string(members1[i].get_value())+'/';
308305
msg+=id2string(members2[i].get_value())+')';
309-
break;
306+
conclusive = true;
310307
}
308+
309+
if(conclusive)
310+
break;
311311
}
312312
}
313313

@@ -331,6 +331,7 @@ void linkingt::detailed_conflict_report_rec(
331331
msg="parameter counts differ (";
332332
msg+=std::to_string(parameters1.size())+'/';
333333
msg+=std::to_string(parameters2.size())+')';
334+
conclusive = true;
334335
}
335336
else if(!base_type_eq(return_type1, return_type2, ns))
336337
{
@@ -339,13 +340,15 @@ void linkingt::detailed_conflict_report_rec(
339340
constant_exprt(std::to_string(-1), integer_typet()));
340341

341342
if(depth>0)
342-
detailed_conflict_report_rec(
343+
{
344+
conclusive = detailed_conflict_report_rec(
343345
old_symbol,
344346
new_symbol,
345347
return_type1,
346348
return_type2,
347-
depth-1,
349+
depth - 1,
348350
conflict_path);
351+
}
349352
else
350353
msg="return types differ";
351354
}
@@ -363,25 +366,31 @@ void linkingt::detailed_conflict_report_rec(
363366
constant_exprt(std::to_string(i), integer_typet()));
364367

365368
if(depth>0)
366-
detailed_conflict_report_rec(
369+
{
370+
conclusive = detailed_conflict_report_rec(
367371
old_symbol,
368372
new_symbol,
369373
subtype1,
370374
subtype2,
371-
depth-1,
375+
depth - 1,
372376
conflict_path);
377+
}
373378
else
374379
msg="parameter types differ";
380+
}
375381

382+
if(conclusive)
376383
break;
377-
}
378384
}
379385
}
380386
}
381387
else
388+
{
382389
msg="conflict on POD";
390+
conclusive = true;
391+
}
383392

384-
if(!msg.empty())
393+
if(conclusive && !msg.empty())
385394
{
386395
error() << '\n';
387396
error() << "reason for conflict at "
@@ -395,6 +404,8 @@ void linkingt::detailed_conflict_report_rec(
395404
#ifdef DEBUG
396405
debug() << "<END DEPTH " << depth << ">" << eom;
397406
#endif
407+
408+
return conclusive;
398409
}
399410

400411
void linkingt::link_error(
@@ -692,8 +703,16 @@ void linkingt::duplicate_code_symbol(
692703
old_symbol.value.is_nil()!=new_symbol.value.is_nil())
693704
{
694705
if(warn_msg.empty())
706+
{
695707
warn_msg="pointer parameter types differ between "
696708
"declaration and definition";
709+
detailed_conflict_report(
710+
old_symbol,
711+
new_symbol,
712+
conflicts.front().first,
713+
conflicts.front().second);
714+
}
715+
697716
replace=new_symbol.value.is_not_nil();
698717
}
699718
// transparent union with (or entirely without) implementation is

src/linking/linking_class.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,10 @@ class linkingt:public typecheckt
131131
return type_to_string_verbose(symbol, symbol.type);
132132
}
133133

134-
void detailed_conflict_report_rec(
134+
/// Returns true iff the conflict report on a particular branch of the tree of
135+
/// types was a definitive result, and not contingent on conflicts within a
136+
/// tag type.
137+
bool detailed_conflict_report_rec(
135138
const symbolt &old_symbol,
136139
const symbolt &new_symbol,
137140
const typet &type1,

0 commit comments

Comments
 (0)