Skip to content

replace incomplete compound types #3643

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 2 commits into from
Jan 8, 2019
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
6 changes: 1 addition & 5 deletions src/ansi-c/c_typecast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ bool check_c_implicit_typecast(
src_type_id==ID_signedbv ||
src_type_id==ID_c_enum ||
src_type_id==ID_c_enum_tag ||
src_type_id==ID_incomplete_c_enum ||
src_type_id==ID_c_bool)
{
if(dest_type.id()==ID_unsignedbv ||
Expand All @@ -171,7 +170,6 @@ bool check_c_implicit_typecast(
dest_type.id()==ID_pointer ||
dest_type.id()==ID_c_enum ||
dest_type.id()==ID_c_enum_tag ||
dest_type.id()==ID_incomplete_c_enum ||
dest_type.id()==ID_complex)
return false;
}
Expand Down Expand Up @@ -345,9 +343,7 @@ c_typecastt::c_typet c_typecastt::get_c_type(
{
return PTR;
}
else if(type.id()==ID_c_enum ||
type.id()==ID_c_enum_tag ||
type.id()==ID_incomplete_c_enum)
else if(type.id() == ID_c_enum || type.id() == ID_c_enum_tag)
{
return INT;
}
Expand Down
62 changes: 30 additions & 32 deletions src/ansi-c/c_typecheck_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,15 @@ void c_typecheck_baset::typecheck_symbol(symbolt &symbol)
}

// set the pretty name
if(symbol.is_type &&
(final_type.id()==ID_struct ||
final_type.id()==ID_incomplete_struct))
if(symbol.is_type && final_type.id() == ID_struct)
{
symbol.pretty_name="struct "+id2string(symbol.base_name);
}
else if(symbol.is_type &&
(final_type.id()==ID_union ||
final_type.id()==ID_incomplete_union))
else if(symbol.is_type && final_type.id() == ID_union)
{
symbol.pretty_name="union "+id2string(symbol.base_name);
}
else if(symbol.is_type &&
(final_type.id()==ID_c_enum ||
final_type.id()==ID_incomplete_c_enum))
else if(symbol.is_type && final_type.id() == ID_c_enum)
{
symbol.pretty_name="enum "+id2string(symbol.base_name);
}
Expand Down Expand Up @@ -176,12 +170,21 @@ void c_typecheck_baset::typecheck_redefinition_type(
const typet &final_new=follow(new_symbol.type);

// see if we had something incomplete before
if(final_old.id()==ID_incomplete_struct ||
final_old.id()==ID_incomplete_union ||
final_old.id()==ID_incomplete_c_enum)
if(
(final_old.id() == ID_struct &&
to_struct_type(final_old).is_incomplete()) ||
(final_old.id() == ID_union && to_union_type(final_old).is_incomplete()) ||
(final_old.id() == ID_c_enum && to_c_enum_type(final_old).is_incomplete()))
{
// new one complete?
if("incomplete_"+final_new.id_string()==final_old.id_string())
// is the new one complete?
if(
final_new.id() == final_old.id() &&
((final_new.id() == ID_struct &&
!to_struct_type(final_new).is_incomplete()) ||
(final_new.id() == ID_union &&
!to_union_type(final_new).is_incomplete()) ||
(final_new.id() == ID_c_enum &&
!to_c_enum_type(final_new).is_incomplete())))
{
// overwrite location
old_symbol.location=new_symbol.location;
Expand All @@ -190,7 +193,7 @@ void c_typecheck_baset::typecheck_redefinition_type(
old_symbol.type.swap(new_symbol.type);
}
else if(new_symbol.type.id()==old_symbol.type.id())
return;
return; // ignore
else
{
error().source_location=new_symbol.location;
Expand All @@ -203,11 +206,15 @@ void c_typecheck_baset::typecheck_redefinition_type(
else
{
// see if new one is just a tag
if(final_new.id()==ID_incomplete_struct ||
final_new.id()==ID_incomplete_union ||
final_new.id()==ID_incomplete_c_enum)
if(
(final_new.id() == ID_struct &&
to_struct_type(final_new).is_incomplete()) ||
(final_new.id() == ID_union &&
to_union_type(final_new).is_incomplete()) ||
(final_new.id() == ID_c_enum &&
to_c_enum_type(final_new).is_incomplete()))
{
if("incomplete_"+final_old.id_string()==final_new.id_string())
if(final_old.id() == final_new.id())
{
// just ignore silently
}
Expand Down Expand Up @@ -418,13 +425,6 @@ void c_typecheck_baset::typecheck_redefinition_non_type(
PRECONDITION(old_symbol.type.id() != ID_symbol_type);
old_symbol.type=new_symbol.type;
}
else if((final_old.id()==ID_incomplete_c_enum ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we check the new is-incomplete flag here?

final_old.id()==ID_c_enum) &&
(final_new.id()==ID_incomplete_c_enum ||
final_new.id()==ID_c_enum))
{
// this is ok for now
}
else if(final_old.id()==ID_pointer &&
follow(final_old).subtype().id()==ID_code &&
to_code_type(follow(final_old).subtype()).has_ellipsis() &&
Expand Down Expand Up @@ -477,12 +477,10 @@ void c_typecheck_baset::typecheck_redefinition_non_type(
}
else
{
if(new_symbol.is_macro &&
(final_new.id()==ID_incomplete_c_enum ||
final_new.id()==ID_c_enum) &&
old_symbol.value.is_constant() &&
new_symbol.value.is_constant() &&
old_symbol.value.get(ID_value)==new_symbol.value.get(ID_value))
if(
new_symbol.is_macro && final_new.id() == ID_c_enum &&
old_symbol.value.is_constant() && new_symbol.value.is_constant() &&
old_symbol.value.get(ID_value) == new_symbol.value.get(ID_value))
{
// ignore
}
Expand Down
12 changes: 7 additions & 5 deletions src/ansi-c/c_typecheck_code.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,18 +341,20 @@ void c_typecheck_baset::typecheck_decl(codet &code)

bool c_typecheck_baset::is_complete_type(const typet &type) const
{
if(type.id()==ID_incomplete_struct ||
type.id()==ID_incomplete_union)
return false;
else if(type.id()==ID_array)
if(type.id() == ID_array)
{
if(to_array_type(type).size().is_nil())
return false;
return is_complete_type(type.subtype());
}
else if(type.id()==ID_struct || type.id()==ID_union)
{
for(const auto &c : to_struct_union_type(type).components())
const auto &struct_union_type = to_struct_union_type(type);

if(struct_union_type.is_incomplete())
return false;

for(const auto &c : struct_union_type.components())
if(!is_complete_type(c.type()))
return false;
}
Expand Down
45 changes: 22 additions & 23 deletions src/ansi-c/c_typecheck_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1361,8 +1361,7 @@ void c_typecheck_baset::typecheck_expr_rel(
if(follow(o_type0)==follow(o_type1))
{
const typet &final_type=follow(o_type0);
if(final_type.id()!=ID_array &&
final_type.id()!=ID_incomplete_struct)
if(final_type.id() != ID_array)
{
adjust_float_rel(expr);
return; // no promotion necessary
Expand Down Expand Up @@ -1524,22 +1523,6 @@ void c_typecheck_baset::typecheck_expr_member(exprt &expr)

type = follow(type);

if(type.id()==ID_incomplete_struct)
{
error().source_location = expr.source_location();
error() << "member operator got incomplete struct type "
"on left hand side" << eom;
throw 0;
}

if(type.id()==ID_incomplete_union)
{
error().source_location = expr.source_location();
error() << "member operator got incomplete union type "
"on left hand side" << eom;
throw 0;
}

if(type.id()!=ID_struct &&
type.id()!=ID_union)
{
Expand All @@ -1553,6 +1536,14 @@ void c_typecheck_baset::typecheck_expr_member(exprt &expr)
const struct_union_typet &struct_union_type=
to_struct_union_type(type);

if(struct_union_type.is_incomplete())
{
error().source_location = expr.source_location();
error() << "member operator got incomplete " << type.id()
<< " type on left hand side" << eom;
throw 0;
}

const irep_idt &component_name=
expr.get(ID_component_name);

Expand Down Expand Up @@ -1897,8 +1888,7 @@ void c_typecheck_baset::typecheck_expr_side_effect(side_effect_exprt &expr)

if(final_type0.id()==ID_c_enum_tag)
{
if(follow_tag(to_c_enum_tag_type(final_type0)).id()==
ID_incomplete_c_enum)
if(follow_tag(to_c_enum_tag_type(final_type0)).is_incomplete())
{
error().source_location = expr.source_location();
error() << "operator `" << statement
Expand Down Expand Up @@ -3166,7 +3156,17 @@ void c_typecheck_baset::typecheck_arithmetic_pointer(const exprt &expr)

typet subtype=type.subtype();

if(subtype.id()==ID_incomplete_struct)
if(
subtype.id() == ID_struct_tag &&
follow_tag(to_struct_tag_type(subtype)).is_incomplete())
{
error().source_location = expr.source_location();
error() << "pointer arithmetic with unknown object size" << eom;
throw 0;
}
else if(
subtype.id() == ID_union_tag &&
follow_tag(to_union_tag_type(subtype)).is_incomplete())
{
error().source_location = expr.source_location();
error() << "pointer arithmetic with unknown object size" << eom;
Expand Down Expand Up @@ -3370,8 +3370,7 @@ void c_typecheck_baset::typecheck_side_effect_assignment(

if(underlying_type.id()==ID_c_enum_tag)
{
const typet &c_enum_type=
follow_tag(to_c_enum_tag_type(underlying_type));
const auto &c_enum_type = to_c_enum_tag_type(underlying_type);
underlying_type=c_enum_type.subtype();
}

Expand Down
6 changes: 4 additions & 2 deletions src/ansi-c/c_typecheck_initializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ exprt c_typecheck_baset::do_initializer_rec(
{
const typet &full_type=follow(type);

if(full_type.id()==ID_incomplete_struct)
if(
(full_type.id() == ID_struct || full_type.id() == ID_union) &&
to_struct_union_type(full_type).is_incomplete())
{
error().source_location = value.source_location();
error() << "type `" << to_string(full_type)
error() << "type `" << to_string(type)
<< "' is still incomplete -- cannot initialize" << eom;
throw 0;
}
Expand Down
53 changes: 26 additions & 27 deletions src/ansi-c/c_typecheck_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,9 +523,11 @@ void c_typecheck_baset::typecheck_array_type(array_typet &type)
}

// we don't allow incomplete structs or unions as subtype
const typet &followed_subtype = follow(type.subtype());

if(
follow(type.subtype()).id() == ID_incomplete_struct ||
follow(type.subtype()).id() == ID_incomplete_union)
(followed_subtype.id() == ID_struct || followed_subtype.id() == ID_union) &&
to_struct_union_type(followed_subtype).is_incomplete())
{
// ISO/IEC 9899 6.7.5.2
error().source_location = type.source_location();
Expand Down Expand Up @@ -806,12 +808,8 @@ void c_typecheck_baset::typecheck_compound_type(struct_union_typet &type)

typet new_type=compound_symbol.type;

if(compound_symbol.type.id()==ID_struct)
compound_symbol.type.id(ID_incomplete_struct);
else if(compound_symbol.type.id()==ID_union)
compound_symbol.type.id(ID_incomplete_union);
else
UNREACHABLE;
// mark as incomplete
to_struct_union_type(compound_symbol.type).make_incomplete();

symbolt *new_symbol;
move_symbol(compound_symbol, new_symbol);
Expand All @@ -826,8 +824,9 @@ void c_typecheck_baset::typecheck_compound_type(struct_union_typet &type)
else
{
// yes, it exists already
if(s_it->second.type.id()==ID_incomplete_struct ||
s_it->second.type.id()==ID_incomplete_union)
if(
s_it->second.type.id() == type.id() &&
to_struct_union_type(s_it->second.type).is_incomplete())
{
// Maybe we got a body now.
if(have_body)
Expand All @@ -852,9 +851,9 @@ void c_typecheck_baset::typecheck_compound_type(struct_union_typet &type)

typet tag_type;

if(type.id() == ID_union || type.id() == ID_incomplete_union)
if(type.id() == ID_union)
tag_type = union_tag_typet(identifier);
else if(type.id() == ID_struct || type.id() == ID_incomplete_struct)
else if(type.id() == ID_struct)
tag_type = struct_tag_typet(identifier);
else
UNREACHABLE;
Expand Down Expand Up @@ -1278,13 +1277,20 @@ void c_typecheck_baset::typecheck_c_enum_type(typet &type)
// Yes.
const symbolt &symbol=s_it->second;

if(symbol.type.id()==ID_incomplete_c_enum)
if(symbol.type.id() != ID_c_enum)
{
error().source_location = source_location;
error() << "use of tag that does not match previous declaration" << eom;
throw 0;
}

if(to_c_enum_type(symbol.type).is_incomplete())
{
// Ok, overwrite the type in the symbol table.
// This gives us the members and the subtype.
symbol_table.get_writeable_ref(symbol.name).type=enum_tag_symbol.type;
}
else if(symbol.type.id()==ID_c_enum)
else
{
// We might already have the same anonymous enum, and this is
// simply ok. Note that the C standard treats these as
Expand All @@ -1296,12 +1302,6 @@ void c_typecheck_baset::typecheck_c_enum_type(typet &type)
throw 0;
}
}
else
{
error().source_location=source_location;
error() << "use of tag that does not match previous declaration" << eom;
throw 0;
}
}
else
{
Expand Down Expand Up @@ -1341,8 +1341,7 @@ void c_typecheck_baset::typecheck_c_enum_tag_type(c_enum_tag_typet &type)
// Yes.
const symbolt &symbol=s_it->second;

if(symbol.type.id()!=ID_c_enum &&
symbol.type.id()!=ID_incomplete_c_enum)
if(symbol.type.id() != ID_c_enum)
{
error().source_location=source_location;
error() << "use of tag that does not match previous declaration" << eom;
Expand All @@ -1352,9 +1351,9 @@ void c_typecheck_baset::typecheck_c_enum_tag_type(c_enum_tag_typet &type)
else
{
// no, add it as an incomplete c_enum
typet new_type(ID_incomplete_c_enum);
new_type.subtype()=signed_int_type(); // default
c_enum_typet new_type(signed_int_type()); // default subtype
new_type.add(ID_tag)=tag;
new_type.make_incomplete();

symbolt enum_tag_symbol;

Expand Down Expand Up @@ -1424,10 +1423,10 @@ void c_typecheck_baset::typecheck_c_bit_field_type(c_bit_field_typet &type)
// These point to an enum, which has a sub-subtype,
// which may be smaller or larger than int, and we thus have
// to check.
const typet &c_enum_type=
follow_tag(to_c_enum_tag_type(subtype));
const auto &c_enum_type =
to_c_enum_type(follow_tag(to_c_enum_tag_type(subtype)));

if(c_enum_type.id()==ID_incomplete_c_enum)
if(c_enum_type.is_incomplete())
{
error().source_location=type.source_location();
error() << "bit field has incomplete enum type" << eom;
Expand Down
Loading