Skip to content

Commit 6dc9b9b

Browse files
peterschrammeltautschnig
authored andcommitted
Fix delayed method body conversion for templates
1 parent 4576f14 commit 6dc9b9b

11 files changed

+179
-46
lines changed

regression/cpp/Function_Overloading2/test.desc

+1-1
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

+1-1
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_instantiate_template.cpp

+31-9
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 << std::endl;
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_save_scopet cpp_saved_scope(cpp_scopes);
242250
cpp_saved_template_mapt saved_map(template_map);
@@ -247,7 +255,7 @@ const symbolt &cpp_typecheckt::instantiate_template(
247255
assert(!specialization_template_args.has_unassigned());
248256
assert(!full_template_args.has_unassigned());
249257

250-
#if 0
258+
#ifdef DEBUG
251259
std::cout << "A: <";
252260
forall_expr(it, specialization_template_args.arguments())
253261
{
@@ -258,8 +266,8 @@ const symbolt &cpp_typecheckt::instantiate_template(
258266
else
259267
std::cout << to_string(*it);
260268
}
261-
std::cout << ">\n";
262-
#endif
269+
std::cout << ">\n\n";
270+
#endif
263271

264272
// do we have arguments?
265273
if(full_template_args.arguments().empty())
@@ -377,8 +385,8 @@ const symbolt &cpp_typecheckt::instantiate_template(
377385
instantiated_with.get_sub().push_back(specialization_template_args);
378386
}
379387

380-
#if 0
381-
std::cout << "MAP:\n";
388+
#ifdef DEBUG
389+
std::cout << "CLASS MAP:" << std::endl;
382390
template_map.print(std::cout);
383391
#endif
384392

@@ -436,15 +444,29 @@ const symbolt &cpp_typecheckt::instantiate_template(
436444

437445
// mapping from template arguments to values/types
438446
template_map.build(method_type, specialization_template_args);
447+
#ifdef DEBUG
448+
std::cout << "METHOD MAP:" << std::endl;
449+
template_map.print(std::cout);
450+
#endif
439451

440452
method_decl.remove(ID_template_type);
441453
method_decl.remove(ID_is_template);
442454

443455
convert(method_decl);
444456
}
445457

446-
const symbolt &new_symb=
447-
lookup(new_decl.type().get(ID_identifier));
458+
const irep_idt& new_symb_id = new_decl.type().get(ID_identifier);
459+
symbolt &new_symb = symbol_table.get_writeable_ref(new_symb_id);
460+
461+
//add template arguments to type in order to retrieve template map
462+
// when typechecking function body
463+
new_symb.type.set(ID_C_template, template_type);
464+
new_symb.type.set(ID_C_template_arguments, specialization_template_args);
465+
466+
#ifdef DEBUG
467+
std::cout << "instance symbol: " << new_symb.name << std::endl << std::endl;
468+
std::cout << "template type: " << template_type << std::endl << std::endl;
469+
#endif
448470

449471
return new_symb;
450472
}

src/cpp/cpp_typecheck.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ void cpp_typecheckt::typecheck()
5353
for(auto &item : cpp_parse_tree.items)
5454
convert(item);
5555

56+
typecheck_method_bodies();
57+
5658
static_and_dynamic_initialization();
5759

5860
do_not_typechecked();

src/cpp/cpp_typecheck.h

+3-6
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
// types
350347

@@ -382,7 +379,7 @@ class cpp_typecheckt:public c_typecheck_baset
382379
void typecheck_compound_body(symbolt &symbol);
383380
void typecheck_compound_body(struct_union_typet &type) { UNREACHABLE; }
384381
void typecheck_enum_body(symbolt &symbol);
385-
void typecheck_method_bodies(method_bodiest &);
382+
void typecheck_method_bodies();
386383
void typecheck_compound_bases(struct_typet &type);
387384
void add_anonymous_members_to_scope(const symbolt &struct_union_symbol);
388385

src/cpp/cpp_typecheck_compound_type.cpp

+21-3
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>
@@ -378,7 +382,7 @@ void cpp_typecheckt::typecheck_compound_declarator(
378382
irep_idt identifier;
379383

380384
// the below is a temporary hack
381-
// if(is_method || is_static)d
385+
// if(is_method || is_static)
382386
if(id2string(cpp_scopes.current_scope().prefix).find("#anon")==
383387
std::string::npos ||
384388
is_method || is_static)
@@ -882,12 +886,25 @@ void cpp_typecheckt::typecheck_friend_declaration(
882886
// It should be a friend function.
883887
// Do the declarators.
884888

889+
#ifdef DEBUG
890+
std::cout << "friend declaration: " << declaration.pretty() << std::endl;
891+
#endif
892+
885893
for(auto &sub_it : declaration.declarators())
886894
{
887-
bool has_value=sub_it.value().is_not_nil();
888-
895+
#ifdef DEBUG
896+
std::cout << "decl: " << sub_it->pretty() << "\n with value "
897+
<< sub_it->value().pretty() << std::endl;
898+
std::cout << " scope: " << cpp_scopes.current_scope().prefix << std::endl;
899+
#endif
900+
// In which scope are we going to typecheck this?
901+
#if 0
902+
// TODO: not sure what the value is?!
903+
bool has_value = sub_it.value().is_not_nil();
889904
if(!has_value)
890905
{
906+
// TODO: This doesn't work if we are inside a template class declaration.
907+
891908
// If no value is found, then we jump to the
892909
// global scope, and we convert the declarator
893910
// as if it were declared there
@@ -901,6 +918,7 @@ void cpp_typecheckt::typecheck_friend_declaration(
901918
symbol.type.add("#friends").move_to_sub(symb_expr);
902919
}
903920
else
921+
#endif
904922
{
905923
cpp_declarator_convertert cpp_declarator_converter(*this);
906924
cpp_declarator_converter.is_friend=true;

src/cpp/cpp_typecheck_declaration.cpp

+4-9
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

+23-1
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,8 @@ bool cpp_typecheckt::overloadable(const exprt &expr)
433433
t=t.subtype();
434434

435435
if(t.id()==ID_struct ||
436+
//this might be an incomplete struct (template) here
437+
t.id()==ID_incomplete_struct ||
436438
t.id()==ID_union ||
437439
t.id()==ID_c_enum)
438440
return true;
@@ -603,6 +605,7 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr)
603605
// We try and fail silently, maybe conversions will work
604606
// instead.
605607

608+
//TODO: need to resolve an incomplete struct (template) here
606609
// go into scope of first operand
607610
if(expr.op0().type().id()==ID_symbol &&
608611
follow(expr.op0().type()).id()==ID_struct)
@@ -2362,7 +2365,26 @@ void cpp_typecheckt::typecheck_method_application(
23622365
member_expr.swap(expr.function());
23632366

23642367
const symbolt &symbol=lookup(member_expr.get(ID_component_name));
2365-
add_method_body(&symbol_table.get_writeable_ref(symbol.name));
2368+
symbolt &method_symbol=symbol_table.get_writeable_ref(symbol.name);
2369+
const symbolt &tag_symbol=lookup(symbol.type.get("#member_name"));
2370+
2371+
// build the right template map
2372+
// if this is an instantiated template class method
2373+
if(tag_symbol.type.find(ID_C_template)!=irept())
2374+
{
2375+
cpp_saved_template_mapt saved_map(template_map);
2376+
const irept &template_type=tag_symbol.type.find(ID_C_template);
2377+
const irept &template_args=tag_symbol.type.find(ID_C_template_arguments);
2378+
template_map.build(static_cast<const template_typet &>(template_type),
2379+
static_cast<const cpp_template_args_tct &>(template_args));
2380+
add_method_body(&method_symbol);
2381+
#ifdef DEBUG
2382+
std::cout << "MAP for " << symbol << ":" << std::endl;
2383+
template_map.print(std::cout);
2384+
#endif
2385+
}
2386+
else
2387+
add_method_body(&method_symbol);
23662388

23672389
// build new function expression
23682390
exprt new_function(cpp_symbol_expr(symbol));

src/cpp/cpp_typecheck_method_bodies.cpp

+43-6
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,6 +39,11 @@ 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() &&
3448
!body.is_zero())
3549
{
@@ -39,3 +53,26 @@ void cpp_typecheckt::typecheck_method_bodies(
3953

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

0 commit comments

Comments
 (0)