Skip to content

Commit

Permalink
Merge pull request diffblue#2448 from tautschnig/c++-delayed-body
Browse files Browse the repository at this point in the history
Fix delayed method body conversion for templates
  • Loading branch information
tautschnig authored Jul 7, 2018
2 parents c46d46d + 02e3840 commit 4c6cfc0
Show file tree
Hide file tree
Showing 21 changed files with 182 additions and 57 deletions.
12 changes: 9 additions & 3 deletions regression/cpp/Function_Overloading2/main.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#ifdef __GNUC__
#define NOTHROW __attribute__((nothrow))
#else
#define NOTHROW
#endif

namespace std {
extern "C" {
double fabs(double) __attribute__((nothrow)) ;
double fabs(double) NOTHROW ;
}

__inline float fabs(float x) __attribute__((nothrow));
__inline long double fabs(long double x) __attribute__((nothrow));
__inline float fabs(float x) NOTHROW;
__inline long double fabs(long double x) NOTHROW;

/* original code from CodeWarrior */
template <class _T>
Expand Down
2 changes: 1 addition & 1 deletion regression/cpp/Function_Overloading2/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.cpp

^EXIT=0$
Expand Down
2 changes: 1 addition & 1 deletion regression/cpp/Template_Instantiation5/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.cpp

^EXIT=0$
Expand Down
2 changes: 1 addition & 1 deletion regression/systemc/BitvectorSc1/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.cpp

^EXIT=10$
Expand Down
2 changes: 1 addition & 1 deletion regression/systemc/BitvectorSc2/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.cpp

^EXIT=0$
Expand Down
2 changes: 1 addition & 1 deletion regression/systemc/EqualOp1/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.cpp

^EXIT=0$
Expand Down
2 changes: 1 addition & 1 deletion regression/systemc/EqualOp2/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.cpp

^EXIT=10$
Expand Down
2 changes: 1 addition & 1 deletion regression/systemc/EqualOp3/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.cpp

^EXIT=10$
Expand Down
2 changes: 1 addition & 1 deletion regression/systemc/FunTempl1/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.cpp

^EXIT=0$
Expand Down
2 changes: 1 addition & 1 deletion regression/systemc/SimpleSc1/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.cpp

^EXIT=0$
Expand Down
2 changes: 1 addition & 1 deletion regression/systemc/Template1/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.cpp

^EXIT=0$
Expand Down
3 changes: 0 additions & 3 deletions src/cpp/cpp_declarator_converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,6 @@ void cpp_declarator_convertert::handle_initializer(
// no initial value yet
symbol.value.swap(value);

if(is_code && declarator.type().id()!=ID_template)
cpp_typecheck.add_method_body(&symbol);

if(!is_code)
cpp_typecheck.convert_initializer(symbol);
}
Expand Down
39 changes: 31 additions & 8 deletions src/cpp/cpp_instantiate_template.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Author: Daniel Kroening, [email protected]

#include "cpp_typecheck.h"

#ifdef DEBUG
#include <iostream>
#endif

#include <util/arith_tools.h>
#include <util/base_exceptions.h>
#include <util/simplify_expr.h>
Expand Down Expand Up @@ -220,6 +224,10 @@ const symbolt &cpp_typecheckt::instantiate_template(
const cpp_template_args_tct &full_template_args,
const typet &specialization)
{
#ifdef DEBUG
std::cout << "instantiate_template: " << template_symbol.name << '\n';
#endif

if(instantiation_stack.size()==MAX_DEPTH)
{
error().source_location=source_location;
Expand All @@ -233,10 +241,10 @@ const symbolt &cpp_typecheckt::instantiate_template(
instantiation_stack.back().identifier=template_symbol.name;
instantiation_stack.back().full_template_args=full_template_args;

#if 0
#ifdef DEBUG
std::cout << "L: " << source_location << '\n';
std::cout << "I: " << template_symbol.name << '\n';
#endif
#endif

cpp_saved_template_mapt saved_map(template_map);

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

#if 0
#ifdef DEBUG
std::cout << "A: <";
forall_expr(it, specialization_template_args.arguments())
{
Expand All @@ -257,8 +265,8 @@ const symbolt &cpp_typecheckt::instantiate_template(
else
std::cout << to_string(*it);
}
std::cout << ">\n";
#endif
std::cout << ">\n\n";
#endif

// do we have arguments?
if(full_template_args.arguments().empty())
Expand Down Expand Up @@ -373,8 +381,8 @@ const symbolt &cpp_typecheckt::instantiate_template(
instantiated_with.get_sub().push_back(specialization_template_args);
}

#if 0
std::cout << "MAP:\n";
#ifdef DEBUG
std::cout << "CLASS MAP:\n";
template_map.print(std::cout);
#endif

Expand Down Expand Up @@ -432,14 +440,29 @@ const symbolt &cpp_typecheckt::instantiate_template(

// mapping from template arguments to values/types
template_map.build(method_type, specialization_template_args);
#ifdef DEBUG
std::cout << "METHOD MAP:\n";
template_map.print(std::cout);
#endif

method_decl.remove(ID_template_type);
method_decl.remove(ID_is_template);

convert(method_decl);
}

const symbolt &new_symb = lookup(new_decl.type().get(ID_identifier));
const irep_idt& new_symb_id = new_decl.type().get(ID_identifier);
symbolt &new_symb = symbol_table.get_writeable_ref(new_symb_id);

// add template arguments to type in order to retrieve template map when
// typechecking function body
new_symb.type.set(ID_C_template, template_type);
new_symb.type.set(ID_C_template_arguments, specialization_template_args);

#ifdef DEBUG
std::cout << "instance symbol: " << new_symb.name << "\n\n";
std::cout << "template type: " << template_type.pretty() << "\n\n";
#endif

return new_symb;
}
Expand Down
2 changes: 2 additions & 0 deletions src/cpp/cpp_typecheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ void cpp_typecheckt::typecheck()
for(auto &item : cpp_parse_tree.items)
convert(item);

typecheck_method_bodies();

static_and_dynamic_initialization();

do_not_typechecked();
Expand Down
9 changes: 3 additions & 6 deletions src/cpp/cpp_typecheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,13 +338,10 @@ class cpp_typecheckt:public c_typecheck_baset
};

typedef std::list<method_bodyt> method_bodiest;
std::set<irep_idt> methods_seen;
method_bodiest method_bodies;

void add_method_body(symbolt *_method_symbol)
{
method_bodies.push_back(method_bodyt(
_method_symbol, template_map, instantiation_stack));
}
void add_method_body(symbolt *_method_symbol);

bool builtin_factory(const irep_idt &);

Expand Down Expand Up @@ -384,7 +381,7 @@ class cpp_typecheckt:public c_typecheck_baset
void typecheck_compound_body(symbolt &symbol);
void typecheck_compound_body(struct_union_typet &type) { UNREACHABLE; }
void typecheck_enum_body(symbolt &symbol);
void typecheck_method_bodies(method_bodiest &);
void typecheck_method_bodies();
void typecheck_compound_bases(struct_typet &type);
void add_anonymous_members_to_scope(const symbolt &struct_union_symbol);

Expand Down
6 changes: 5 additions & 1 deletion src/cpp/cpp_typecheck_compound_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Author: Daniel Kroening, [email protected]

#include "cpp_typecheck.h"

#ifdef DEBUG
#include <iostream>
#endif

#include <algorithm>

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

// the below is a temporary hack
// if(is_method || is_static)d
// if(is_method || is_static)
if(id2string(cpp_scopes.current_scope().prefix).find("#anon")==
std::string::npos ||
is_method || is_static)
Expand Down
13 changes: 4 additions & 9 deletions src/cpp/cpp_typecheck_declaration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Author: Daniel Kroening, [email protected]
\********************************************************************/


/// \file
/// C++ Language Type Checking

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

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

// templates are done in a dedicated function
if(declaration.is_template())
convert_template_declaration(declaration);
else
convert_non_template_declaration(declaration);

method_bodiest b;
b.swap(method_bodies);
typecheck_method_bodies(b);
method_bodies.swap(old_method_bodies);
}

void cpp_typecheckt::convert_anonymous_union(
Expand Down
24 changes: 23 additions & 1 deletion src/cpp/cpp_typecheck_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ bool cpp_typecheckt::overloadable(const exprt &expr)
t=t.subtype();

if(t.id()==ID_struct ||
t.id() == ID_incomplete_struct ||
t.id()==ID_union ||
t.id()==ID_c_enum || t.id() == ID_c_enum_tag)
return true;
Expand Down Expand Up @@ -602,6 +603,7 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr)
// We try and fail silently, maybe conversions will work
// instead.

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

const symbolt &symbol=lookup(member_expr.get(ID_component_name));
add_method_body(&symbol_table.get_writeable_ref(symbol.name));
symbolt &method_symbol=symbol_table.get_writeable_ref(symbol.name);
const symbolt &tag_symbol=lookup(symbol.type.get("#member_name"));

// build the right template map
// if this is an instantiated template class method
if(tag_symbol.type.find(ID_C_template)!=irept())
{
cpp_saved_template_mapt saved_map(template_map);
const irept &template_type = tag_symbol.type.find(ID_C_template);
const irept &template_args = tag_symbol.type.find(ID_C_template_arguments);
template_map.build(
static_cast<const template_typet &>(template_type),
static_cast<const cpp_template_args_tct &>(template_args));
add_method_body(&method_symbol);
#ifdef DEBUG
std::cout << "MAP for " << symbol << ":" << std::endl;
template_map.print(std::cout);
#endif
}
else
add_method_body(&method_symbol);

// build new function expression
exprt new_function(cpp_symbol_expr(symbol));
Expand Down
49 changes: 43 additions & 6 deletions src/cpp/cpp_typecheck_method_bodies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,28 @@ Author: Daniel Kroening, [email protected]
/// \file
/// C++ Language Type Checking

#ifdef DEBUG
#include <iostream>
#endif

#include "cpp_typecheck.h"

void cpp_typecheckt::typecheck_method_bodies(
method_bodiest &bodies)
void cpp_typecheckt::typecheck_method_bodies()
{
instantiation_stackt old_instantiation_stack;
old_instantiation_stack.swap(instantiation_stack);

for(auto &b : bodies)
while(!method_bodies.empty())
{
symbolt &method_symbol=*b.method_symbol;
template_map.swap(b.template_map);
instantiation_stack.swap(b.instantiation_stack);
// Dangerous not to take a copy here. We'll have to make sure that
// convert is never called with the same symbol twice.
method_bodyt &method_body = *method_bodies.begin();
symbolt &method_symbol = *method_body.method_symbol;

template_map.swap(method_body.template_map);
instantiation_stack.swap(method_body.instantiation_stack);

method_bodies.erase(method_bodies.begin());

if(method_symbol.name==ID_main)
add_argc_argv(method_symbol);
Expand All @@ -30,9 +39,37 @@ void cpp_typecheckt::typecheck_method_bodies(
if(body.id()=="cpp_not_typechecked")
continue;

#ifdef DEBUG
std::cout << "convert_method_body: " << method_symbol.name << std::endl;
std::cout << " is_not_nil: " << body.is_not_nil() << std::endl;
std::cout << " !is_zero: " << (!body.is_zero()) << std::endl;
#endif
if(body.is_not_nil() && !body.is_zero())
convert_function(method_symbol);
}

old_instantiation_stack.swap(instantiation_stack);
}

void cpp_typecheckt::add_method_body(symbolt *_method_symbol)
{
#ifdef DEBUG
std::cout << "add_method_body: " << _method_symbol->name << std::endl;
#endif

// We have to prevent the same method to be added multiple times
// otherwise we get duplicated symbol prefixes
if(methods_seen.find(_method_symbol->name) != methods_seen.end())
{
#ifdef DEBUG
std::cout << " already exists" << std::endl;
#endif
return;
}
method_bodies.push_back(
method_bodyt(_method_symbol, template_map, instantiation_stack));

// Converting a method body might add method bodies for methods
// that we have already analyzed. Hence, we have to keep track.
methods_seen.insert(_method_symbol->name);
}
Loading

0 comments on commit 4c6cfc0

Please sign in to comment.