Skip to content

Fix delayed method body conversion for templates #2448

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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