Skip to content

Commit f9afff2

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.
1 parent 73a1414 commit f9afff2

File tree

7 files changed

+148
-44
lines changed

7 files changed

+148
-44
lines changed
Lines changed: 12 additions & 0 deletions
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
Lines changed: 9 additions & 0 deletions
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+
}
Lines changed: 16 additions & 0 deletions
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+
}
Lines changed: 17 additions & 0 deletions
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+
}
Lines changed: 29 additions & 0 deletions
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

Lines changed: 62 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -125,25 +125,30 @@ std::string linkingt::type_to_string_verbose(
125125
return type_to_string(symbol.name, type);
126126
}
127127

128-
void linkingt::detailed_conflict_report_rec(
128+
bool linkingt::detailed_conflict_report_rec(
129129
const symbolt &old_symbol,
130130
const symbolt &new_symbol,
131131
const typet &type1,
132132
const typet &type2,
133133
unsigned depth,
134134
exprt &conflict_path)
135135
{
136-
#ifdef DEBUG
136+
bool conclusive = false;
137+
138+
#ifdef DEBUG
137139
debug() << "<BEGIN DEPTH " << depth << ">" << eom;
138-
#endif
140+
#endif
139141

140142
std::string msg;
141143

142144
const typet &t1=follow_tags_symbols(ns, type1);
143145
const typet &t2=follow_tags_symbols(ns, type2);
144146

145147
if(t1.id()!=t2.id())
148+
{
146149
msg="type classes differ";
150+
conclusive = true;
151+
}
147152
else if(t1.id()==ID_pointer ||
148153
t1.id()==ID_array)
149154
{
@@ -153,12 +158,12 @@ void linkingt::detailed_conflict_report_rec(
153158
if(conflict_path.type().id() == ID_pointer)
154159
conflict_path = dereference_exprt(conflict_path);
155160

156-
detailed_conflict_report_rec(
161+
conclusive = detailed_conflict_report_rec(
157162
old_symbol,
158163
new_symbol,
159164
t1.subtype(),
160165
t2.subtype(),
161-
depth-1,
166+
depth - 1,
162167
conflict_path);
163168
}
164169
else if(t1.id()==ID_pointer)
@@ -182,6 +187,7 @@ void linkingt::detailed_conflict_report_rec(
182187
msg="number of members is different (";
183188
msg+=std::to_string(components1.size())+'/';
184189
msg+=std::to_string(components2.size())+')';
190+
conclusive = true;
185191
}
186192
else
187193
{
@@ -195,7 +201,7 @@ void linkingt::detailed_conflict_report_rec(
195201
msg="names of member "+std::to_string(i)+" differ (";
196202
msg+=id2string(components1[i].get_name())+'/';
197203
msg+=id2string(components2[i].get_name())+')';
198-
break;
204+
conclusive = true;
199205
}
200206
else if(!base_type_eq(subtype1, subtype2, ns))
201207
{
@@ -208,6 +214,7 @@ void linkingt::detailed_conflict_report_rec(
208214
e.id()==ID_index)
209215
{
210216
parent_types.insert(e.type());
217+
parent_types.insert(follow_tags_symbols(ns, e.type()));
211218
if(e.id() == ID_dereference)
212219
e = to_dereference_expr(e).pointer();
213220
else if(e.id() == ID_member)
@@ -218,44 +225,32 @@ void linkingt::detailed_conflict_report_rec(
218225
UNREACHABLE;
219226
}
220227

221-
conflict_path=conflict_path_before;
222-
conflict_path.type()=t1;
223-
conflict_path=
224-
member_exprt(conflict_path, components1[i]);
225-
226-
if(depth>0 &&
227-
parent_types.find(t1)==parent_types.end())
228-
detailed_conflict_report_rec(
229-
old_symbol,
230-
new_symbol,
231-
subtype1,
232-
subtype2,
233-
depth-1,
234-
conflict_path);
235-
else
228+
if(parent_types.find(subtype1) == parent_types.end())
236229
{
237-
msg="type of member "+
238-
id2string(components1[i].get_name())+
239-
" differs";
240-
if(depth>0)
230+
conflict_path = conflict_path_before;
231+
conflict_path.type() = t1;
232+
conflict_path = member_exprt(conflict_path, components1[i]);
233+
234+
if(depth > 0)
241235
{
242-
std::string msg_bak;
243-
msg_bak.swap(msg);
244-
symbol_exprt c = symbol_exprt::typeless(ID_C_this);
245-
detailed_conflict_report_rec(
236+
conclusive = detailed_conflict_report_rec(
246237
old_symbol,
247238
new_symbol,
248239
subtype1,
249240
subtype2,
250-
depth-1,
251-
c);
252-
msg.swap(msg_bak);
241+
depth - 1,
242+
conflict_path);
253243
}
254244
}
255-
256-
if(parent_types.find(t1)==parent_types.end())
257-
break;
245+
else
246+
{
247+
msg = "type of member " + id2string(components1[i].get_name()) +
248+
" differs (recursive)";
249+
}
258250
}
251+
252+
if(conclusive)
253+
break;
259254
}
260255
}
261256
}
@@ -272,12 +267,14 @@ void linkingt::detailed_conflict_report_rec(
272267
msg="enum value types are different (";
273268
msg += type_to_string(old_symbol.name, t1.subtype()) + '/';
274269
msg += type_to_string(new_symbol.name, t2.subtype()) + ')';
270+
conclusive = true;
275271
}
276272
else if(members1.size()!=members2.size())
277273
{
278274
msg="number of enum members is different (";
279275
msg+=std::to_string(members1.size())+'/';
280276
msg+=std::to_string(members2.size())+')';
277+
conclusive = true;
281278
}
282279
else
283280
{
@@ -288,15 +285,18 @@ void linkingt::detailed_conflict_report_rec(
288285
msg="names of member "+std::to_string(i)+" differ (";
289286
msg+=id2string(members1[i].get_base_name())+'/';
290287
msg+=id2string(members2[i].get_base_name())+')';
291-
break;
288+
conclusive = true;
292289
}
293290
else if(members1[i].get_value()!=members2[i].get_value())
294291
{
295292
msg="values of member "+std::to_string(i)+" differ (";
296293
msg+=id2string(members1[i].get_value())+'/';
297294
msg+=id2string(members2[i].get_value())+')';
298-
break;
295+
conclusive = true;
299296
}
297+
298+
if(conclusive)
299+
break;
300300
}
301301
}
302302

@@ -320,6 +320,7 @@ void linkingt::detailed_conflict_report_rec(
320320
msg="parameter counts differ (";
321321
msg+=std::to_string(parameters1.size())+'/';
322322
msg+=std::to_string(parameters2.size())+')';
323+
conclusive = true;
323324
}
324325
else if(!base_type_eq(return_type1, return_type2, ns))
325326
{
@@ -328,13 +329,15 @@ void linkingt::detailed_conflict_report_rec(
328329
constant_exprt(std::to_string(-1), integer_typet()));
329330

330331
if(depth>0)
331-
detailed_conflict_report_rec(
332+
{
333+
conclusive = detailed_conflict_report_rec(
332334
old_symbol,
333335
new_symbol,
334336
return_type1,
335337
return_type2,
336-
depth-1,
338+
depth - 1,
337339
conflict_path);
340+
}
338341
else
339342
msg="return types differ";
340343
}
@@ -352,25 +355,31 @@ void linkingt::detailed_conflict_report_rec(
352355
constant_exprt(std::to_string(i), integer_typet()));
353356

354357
if(depth>0)
355-
detailed_conflict_report_rec(
358+
{
359+
conclusive = detailed_conflict_report_rec(
356360
old_symbol,
357361
new_symbol,
358362
subtype1,
359363
subtype2,
360-
depth-1,
364+
depth - 1,
361365
conflict_path);
366+
}
362367
else
363368
msg="parameter types differ";
369+
}
364370

371+
if(conclusive)
365372
break;
366-
}
367373
}
368374
}
369375
}
370376
else
377+
{
371378
msg="conflict on POD";
379+
conclusive = true;
380+
}
372381

373-
if(!msg.empty())
382+
if(conclusive && !msg.empty())
374383
{
375384
error() << '\n';
376385
error() << "reason for conflict at "
@@ -384,6 +393,8 @@ void linkingt::detailed_conflict_report_rec(
384393
#ifdef DEBUG
385394
debug() << "<END DEPTH " << depth << ">" << eom;
386395
#endif
396+
397+
return conclusive;
387398
}
388399

389400
void linkingt::link_error(
@@ -681,8 +692,16 @@ void linkingt::duplicate_code_symbol(
681692
old_symbol.value.is_nil()!=new_symbol.value.is_nil())
682693
{
683694
if(warn_msg.empty())
695+
{
684696
warn_msg="pointer parameter types differ between "
685697
"declaration and definition";
698+
detailed_conflict_report(
699+
old_symbol,
700+
new_symbol,
701+
conflicts.front().first,
702+
conflicts.front().second);
703+
}
704+
686705
replace=new_symbol.value.is_not_nil();
687706
}
688707
// transparent union with (or entirely without) implementation is

src/linking/linking_class.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ 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 conclusive.
136+
bool detailed_conflict_report_rec(
135137
const symbolt &old_symbol,
136138
const symbolt &new_symbol,
137139
const typet &type1,

0 commit comments

Comments
 (0)