Skip to content

Commit 4c6cfc0

Browse files
authored
Merge pull request diffblue#2448 from tautschnig/c++-delayed-body
Fix delayed method body conversion for templates
2 parents c46d46d + 02e3840 commit 4c6cfc0

21 files changed

+182
-57
lines changed

regression/cpp/Function_Overloading2/main.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
#ifdef __GNUC__
2+
#define NOTHROW __attribute__((nothrow))
3+
#else
4+
#define NOTHROW
5+
#endif
6+
17
namespace std {
28
extern "C" {
3-
double fabs(double) __attribute__((nothrow)) ;
9+
double fabs(double) NOTHROW ;
410
}
511

6-
__inline float fabs(float x) __attribute__((nothrow));
7-
__inline long double fabs(long double x) __attribute__((nothrow));
12+
__inline float fabs(float x) NOTHROW;
13+
__inline long double fabs(long double x) NOTHROW;
814

915
/* original code from CodeWarrior */
1016
template <class _T>

regression/cpp/Function_Overloading2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=0$

regression/cpp/Template_Instantiation5/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=0$

regression/systemc/BitvectorSc1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=10$

regression/systemc/BitvectorSc2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=0$

regression/systemc/EqualOp1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=0$

regression/systemc/EqualOp2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=10$

regression/systemc/EqualOp3/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=10$

regression/systemc/FunTempl1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=0$

regression/systemc/SimpleSc1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=0$

regression/systemc/Template1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=0$

src/cpp/cpp_declarator_converter.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,6 @@ void cpp_declarator_convertert::handle_initializer(
346346
// no initial value yet
347347
symbol.value.swap(value);
348348

349-
if(is_code && declarator.type().id()!=ID_template)
350-
cpp_typecheck.add_method_body(&symbol);
351-
352349
if(!is_code)
353350
cpp_typecheck.convert_initializer(symbol);
354351
}

src/cpp/cpp_instantiate_template.cpp

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include "cpp_typecheck.h"
1313

14+
#ifdef DEBUG
15+
#include <iostream>
16+
#endif
17+
1418
#include <util/arith_tools.h>
1519
#include <util/base_exceptions.h>
1620
#include <util/simplify_expr.h>
@@ -220,6 +224,10 @@ const symbolt &cpp_typecheckt::instantiate_template(
220224
const cpp_template_args_tct &full_template_args,
221225
const typet &specialization)
222226
{
227+
#ifdef DEBUG
228+
std::cout << "instantiate_template: " << template_symbol.name << '\n';
229+
#endif
230+
223231
if(instantiation_stack.size()==MAX_DEPTH)
224232
{
225233
error().source_location=source_location;
@@ -233,10 +241,10 @@ const symbolt &cpp_typecheckt::instantiate_template(
233241
instantiation_stack.back().identifier=template_symbol.name;
234242
instantiation_stack.back().full_template_args=full_template_args;
235243

236-
#if 0
244+
#ifdef DEBUG
237245
std::cout << "L: " << source_location << '\n';
238246
std::cout << "I: " << template_symbol.name << '\n';
239-
#endif
247+
#endif
240248

241249
cpp_saved_template_mapt saved_map(template_map);
242250

@@ -246,7 +254,7 @@ const symbolt &cpp_typecheckt::instantiate_template(
246254
assert(!specialization_template_args.has_unassigned());
247255
assert(!full_template_args.has_unassigned());
248256

249-
#if 0
257+
#ifdef DEBUG
250258
std::cout << "A: <";
251259
forall_expr(it, specialization_template_args.arguments())
252260
{
@@ -257,8 +265,8 @@ const symbolt &cpp_typecheckt::instantiate_template(
257265
else
258266
std::cout << to_string(*it);
259267
}
260-
std::cout << ">\n";
261-
#endif
268+
std::cout << ">\n\n";
269+
#endif
262270

263271
// do we have arguments?
264272
if(full_template_args.arguments().empty())
@@ -373,8 +381,8 @@ const symbolt &cpp_typecheckt::instantiate_template(
373381
instantiated_with.get_sub().push_back(specialization_template_args);
374382
}
375383

376-
#if 0
377-
std::cout << "MAP:\n";
384+
#ifdef DEBUG
385+
std::cout << "CLASS MAP:\n";
378386
template_map.print(std::cout);
379387
#endif
380388

@@ -432,14 +440,29 @@ const symbolt &cpp_typecheckt::instantiate_template(
432440

433441
// mapping from template arguments to values/types
434442
template_map.build(method_type, specialization_template_args);
443+
#ifdef DEBUG
444+
std::cout << "METHOD MAP:\n";
445+
template_map.print(std::cout);
446+
#endif
435447

436448
method_decl.remove(ID_template_type);
437449
method_decl.remove(ID_is_template);
438450

439451
convert(method_decl);
440452
}
441453

442-
const symbolt &new_symb = lookup(new_decl.type().get(ID_identifier));
454+
const irep_idt& new_symb_id = new_decl.type().get(ID_identifier);
455+
symbolt &new_symb = symbol_table.get_writeable_ref(new_symb_id);
456+
457+
// add template arguments to type in order to retrieve template map when
458+
// typechecking function body
459+
new_symb.type.set(ID_C_template, template_type);
460+
new_symb.type.set(ID_C_template_arguments, specialization_template_args);
461+
462+
#ifdef DEBUG
463+
std::cout << "instance symbol: " << new_symb.name << "\n\n";
464+
std::cout << "template type: " << template_type.pretty() << "\n\n";
465+
#endif
443466

444467
return new_symb;
445468
}

src/cpp/cpp_typecheck.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ void cpp_typecheckt::typecheck()
5454
for(auto &item : cpp_parse_tree.items)
5555
convert(item);
5656

57+
typecheck_method_bodies();
58+
5759
static_and_dynamic_initialization();
5860

5961
do_not_typechecked();

src/cpp/cpp_typecheck.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -338,13 +338,10 @@ class cpp_typecheckt:public c_typecheck_baset
338338
};
339339

340340
typedef std::list<method_bodyt> method_bodiest;
341+
std::set<irep_idt> methods_seen;
341342
method_bodiest method_bodies;
342343

343-
void add_method_body(symbolt *_method_symbol)
344-
{
345-
method_bodies.push_back(method_bodyt(
346-
_method_symbol, template_map, instantiation_stack));
347-
}
344+
void add_method_body(symbolt *_method_symbol);
348345

349346
bool builtin_factory(const irep_idt &);
350347

@@ -384,7 +381,7 @@ class cpp_typecheckt:public c_typecheck_baset
384381
void typecheck_compound_body(symbolt &symbol);
385382
void typecheck_compound_body(struct_union_typet &type) { UNREACHABLE; }
386383
void typecheck_enum_body(symbolt &symbol);
387-
void typecheck_method_bodies(method_bodiest &);
384+
void typecheck_method_bodies();
388385
void typecheck_compound_bases(struct_typet &type);
389386
void add_anonymous_members_to_scope(const symbolt &struct_union_symbol);
390387

src/cpp/cpp_typecheck_compound_type.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include "cpp_typecheck.h"
1313

14+
#ifdef DEBUG
15+
#include <iostream>
16+
#endif
17+
1418
#include <algorithm>
1519

1620
#include <util/arith_tools.h>
@@ -395,7 +399,7 @@ void cpp_typecheckt::typecheck_compound_declarator(
395399
irep_idt identifier;
396400

397401
// the below is a temporary hack
398-
// if(is_method || is_static)d
402+
// if(is_method || is_static)
399403
if(id2string(cpp_scopes.current_scope().prefix).find("#anon")==
400404
std::string::npos ||
401405
is_method || is_static)

src/cpp/cpp_typecheck_declaration.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Author: Daniel Kroening, [email protected]
66
77
\********************************************************************/
88

9+
910
/// \file
1011
/// C++ Language Type Checking
1112

@@ -19,21 +20,15 @@ void cpp_typecheckt::convert(cpp_declarationt &declaration)
1920
if(declaration.is_empty())
2021
return;
2122

22-
// Record the function bodies so we can check them later.
23-
// This function is used recursively, so we save them.
24-
method_bodiest old_method_bodies;
25-
old_method_bodies.swap(method_bodies);
23+
// The function bodies must not be checked here,
24+
// but only at the very end when all declarations have been
25+
// processed (or considering forward declarations at least)
2626

2727
// templates are done in a dedicated function
2828
if(declaration.is_template())
2929
convert_template_declaration(declaration);
3030
else
3131
convert_non_template_declaration(declaration);
32-
33-
method_bodiest b;
34-
b.swap(method_bodies);
35-
typecheck_method_bodies(b);
36-
method_bodies.swap(old_method_bodies);
3732
}
3833

3934
void cpp_typecheckt::convert_anonymous_union(

src/cpp/cpp_typecheck_expr.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ bool cpp_typecheckt::overloadable(const exprt &expr)
432432
t=t.subtype();
433433

434434
if(t.id()==ID_struct ||
435+
t.id() == ID_incomplete_struct ||
435436
t.id()==ID_union ||
436437
t.id()==ID_c_enum || t.id() == ID_c_enum_tag)
437438
return true;
@@ -602,6 +603,7 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr)
602603
// We try and fail silently, maybe conversions will work
603604
// instead.
604605

606+
// TODO: need to resolve an incomplete struct (template) here
605607
// go into scope of first operand
606608
if(expr.op0().type().id()==ID_symbol &&
607609
follow(expr.op0().type()).id()==ID_struct)
@@ -2380,7 +2382,27 @@ void cpp_typecheckt::typecheck_method_application(
23802382
member_expr.swap(expr.function());
23812383

23822384
const symbolt &symbol=lookup(member_expr.get(ID_component_name));
2383-
add_method_body(&symbol_table.get_writeable_ref(symbol.name));
2385+
symbolt &method_symbol=symbol_table.get_writeable_ref(symbol.name);
2386+
const symbolt &tag_symbol=lookup(symbol.type.get("#member_name"));
2387+
2388+
// build the right template map
2389+
// if this is an instantiated template class method
2390+
if(tag_symbol.type.find(ID_C_template)!=irept())
2391+
{
2392+
cpp_saved_template_mapt saved_map(template_map);
2393+
const irept &template_type = tag_symbol.type.find(ID_C_template);
2394+
const irept &template_args = tag_symbol.type.find(ID_C_template_arguments);
2395+
template_map.build(
2396+
static_cast<const template_typet &>(template_type),
2397+
static_cast<const cpp_template_args_tct &>(template_args));
2398+
add_method_body(&method_symbol);
2399+
#ifdef DEBUG
2400+
std::cout << "MAP for " << symbol << ":" << std::endl;
2401+
template_map.print(std::cout);
2402+
#endif
2403+
}
2404+
else
2405+
add_method_body(&method_symbol);
23842406

23852407
// build new function expression
23862408
exprt new_function(cpp_symbol_expr(symbol));

src/cpp/cpp_typecheck_method_bodies.cpp

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,28 @@ Author: Daniel Kroening, [email protected]
99
/// \file
1010
/// C++ Language Type Checking
1111

12+
#ifdef DEBUG
13+
#include <iostream>
14+
#endif
15+
1216
#include "cpp_typecheck.h"
1317

14-
void cpp_typecheckt::typecheck_method_bodies(
15-
method_bodiest &bodies)
18+
void cpp_typecheckt::typecheck_method_bodies()
1619
{
1720
instantiation_stackt old_instantiation_stack;
1821
old_instantiation_stack.swap(instantiation_stack);
1922

20-
for(auto &b : bodies)
23+
while(!method_bodies.empty())
2124
{
22-
symbolt &method_symbol=*b.method_symbol;
23-
template_map.swap(b.template_map);
24-
instantiation_stack.swap(b.instantiation_stack);
25+
// Dangerous not to take a copy here. We'll have to make sure that
26+
// convert is never called with the same symbol twice.
27+
method_bodyt &method_body = *method_bodies.begin();
28+
symbolt &method_symbol = *method_body.method_symbol;
29+
30+
template_map.swap(method_body.template_map);
31+
instantiation_stack.swap(method_body.instantiation_stack);
32+
33+
method_bodies.erase(method_bodies.begin());
2534

2635
if(method_symbol.name==ID_main)
2736
add_argc_argv(method_symbol);
@@ -30,9 +39,37 @@ void cpp_typecheckt::typecheck_method_bodies(
3039
if(body.id()=="cpp_not_typechecked")
3140
continue;
3241

42+
#ifdef DEBUG
43+
std::cout << "convert_method_body: " << method_symbol.name << std::endl;
44+
std::cout << " is_not_nil: " << body.is_not_nil() << std::endl;
45+
std::cout << " !is_zero: " << (!body.is_zero()) << std::endl;
46+
#endif
3347
if(body.is_not_nil() && !body.is_zero())
3448
convert_function(method_symbol);
3549
}
3650

3751
old_instantiation_stack.swap(instantiation_stack);
3852
}
53+
54+
void cpp_typecheckt::add_method_body(symbolt *_method_symbol)
55+
{
56+
#ifdef DEBUG
57+
std::cout << "add_method_body: " << _method_symbol->name << std::endl;
58+
#endif
59+
60+
// We have to prevent the same method to be added multiple times
61+
// otherwise we get duplicated symbol prefixes
62+
if(methods_seen.find(_method_symbol->name) != methods_seen.end())
63+
{
64+
#ifdef DEBUG
65+
std::cout << " already exists" << std::endl;
66+
#endif
67+
return;
68+
}
69+
method_bodies.push_back(
70+
method_bodyt(_method_symbol, template_map, instantiation_stack));
71+
72+
// Converting a method body might add method bodies for methods
73+
// that we have already analyzed. Hence, we have to keep track.
74+
methods_seen.insert(_method_symbol->name);
75+
}

0 commit comments

Comments
 (0)