Skip to content

Commit

Permalink
Handle array initialization with a non-array gracefully
Browse files Browse the repository at this point in the history
clang -Wall says:

Struct_Initialization1/main.c:16:38: warning: suggest braces around initialization of subobject [-Wmissing-braces]
struct _classinfo nullclass1 = { 42, 1, 2, 3, 4 };
                                     ^~~~
                                     {   }
and then constructs a suitable object.

Our implementation now attempts to build an initializer list if a
variable-length array is encountered; if this succeeds, the same suitable object
is constructed. Variable-length arrays in the middle of a struct are not
permitted (neither by GCC nor Clang or our C front-end).
  • Loading branch information
tautschnig committed Jul 19, 2017
1 parent 13a7538 commit 9740142
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 27 deletions.
10 changes: 8 additions & 2 deletions regression/ansi-c/Struct_Initialization1/main.c
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
#define STATIC_ASSERT(condition) \
int some_array##__LINE__[(condition) ? 1 : -1]

struct A {
int x;
int y;
};

struct _classinfo {
char a;
struct A s;
int *interfaces[];
};

struct _classinfo nullclass1 = { 42, 0, 0 };
struct _classinfo nullclass2 = { 42, { 0, 0 } };
struct _classinfo nullclass1 = { 42, 1, 2, 3, 4 };
struct _classinfo nullclass2 = { 42, { 1, 2 }, { 3, 4 } };

STATIC_ASSERT(sizeof(nullclass1)==sizeof(struct _classinfo));
STATIC_ASSERT(sizeof(nullclass2)==sizeof(struct _classinfo));
Expand Down
2 changes: 1 addition & 1 deletion regression/ansi-c/Struct_Initialization1/test.desc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KNOWNBUG
CORE
main.c

^EXIT=0$
Expand Down
24 changes: 24 additions & 0 deletions regression/ansi-c/Struct_Initialization2/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#define STATIC_ASSERT(condition) \
int some_array##__LINE__[(condition) ? 1 : -1]

struct A {
int x;
int y;
int arr[];
};

struct _classinfo {
char a;
struct A s;
int *interfaces[];
};

struct _classinfo nullclass1 = { 42, 1, 2, 0, 3, 4 };
struct _classinfo nullclass2 = { 42, { 1, 2, 0 }, { 3, 4 } };

STATIC_ASSERT(sizeof(nullclass1)==sizeof(struct _classinfo));
STATIC_ASSERT(sizeof(nullclass2)==sizeof(struct _classinfo));

int main()
{
}
10 changes: 10 additions & 0 deletions regression/ansi-c/Struct_Initialization2/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c

^EXIT=(64|1)$
^SIGNAL=0$
^CONVERSION ERROR$
--
^warning: ignoring
--
variable-length arrays in the middle of a struct are not permitted
5 changes: 3 additions & 2 deletions src/ansi-c/c_typecheck_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,11 @@ class c_typecheck_baset:
const typet &type,
bool force_constant);

virtual void do_designated_initializer(
virtual exprt::operandst::const_iterator do_designated_initializer(
exprt &result,
designatort &designator,
const exprt &value,
const exprt &initializer_list,
exprt::operandst::const_iterator init_it,
bool force_constant);

designatort make_designator(const typet &type, const exprt &src);
Expand Down
77 changes: 56 additions & 21 deletions src/ansi-c/c_typecheck_initializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,7 @@ void c_typecheck_baset::designator_enter(
const typet &type,
designatort &designator)
{
designatort::entryt entry;
entry.type=type;
entry.index=0;
designatort::entryt entry(type);

const typet &full_type=follow(type);

Expand All @@ -268,6 +266,8 @@ void c_typecheck_baset::designator_enter(

entry.size=struct_type.components().size();
entry.subtype.make_nil();
// only a top-level struct may end with a variable-length array
entry.vla_permitted=designator.empty();

for(struct_typet::componentst::const_iterator
it=struct_type.components().begin();
Expand Down Expand Up @@ -351,12 +351,16 @@ void c_typecheck_baset::designator_enter(

/// \param pre:initialized result, designator
/// \return sets result
void c_typecheck_baset::do_designated_initializer(
exprt::operandst::const_iterator c_typecheck_baset::do_designated_initializer(
exprt &result,
designatort &designator,
const exprt &value,
const exprt &initializer_list,
exprt::operandst::const_iterator init_it,
bool force_constant)
{
// copy the value, we may need to adjust it
exprt value=*init_it;

assert(!designator.empty());

if(value.id()==ID_designated_initializer)
Expand All @@ -370,8 +374,10 @@ void c_typecheck_baset::do_designated_initializer(

assert(!designator.empty());

return do_designated_initializer(
result, designator, value.op0(), force_constant);
// discard the return value
do_designated_initializer(
result, designator, value, value.operands().begin(), force_constant);
return ++init_it;
}

exprt *dest=&result;
Expand Down Expand Up @@ -503,7 +509,7 @@ void c_typecheck_baset::do_designated_initializer(

assert(full_type==follow(dest->type()));

return; // done
return ++init_it; // done
}

// union? The component in the zero initializer might
Expand Down Expand Up @@ -537,7 +543,7 @@ void c_typecheck_baset::do_designated_initializer(
if(value.id()==ID_initializer_list)
{
*dest=do_initializer_rec(value, type, force_constant);
return; // done
return ++init_it; // done
}
else if(value.id()==ID_string_constant)
{
Expand All @@ -549,7 +555,7 @@ void c_typecheck_baset::do_designated_initializer(
follow(full_type.subtype()).id()==ID_unsignedbv))
{
*dest=do_initializer_rec(value, type, force_constant);
return; // done
return ++init_it; // done
}
}
else if(follow(value.type())==full_type)
Expand All @@ -562,7 +568,7 @@ void c_typecheck_baset::do_designated_initializer(
full_type.id()==ID_vector)
{
*dest=value;
return; // done
return ++init_it; // done
}
}

Expand All @@ -574,21 +580,49 @@ void c_typecheck_baset::do_designated_initializer(
// we are initializing a compound type, and enter it!
// this may change the type, full_type might not be valid any more
const typet dest_type=full_type;
const bool vla_permitted=designator.back().vla_permitted;
designator_enter(type, designator);

// GCC permits (though issuing a warning with -Wall) composite
// types built from flat initializer lists
if(dest->operands().empty())
{
err_location(value);
error() << "cannot initialize type `"
<< to_string(dest_type) << "' using value `"
<< to_string(value) << "'" << eom;
throw 0;
warning().source_location=value.find_source_location();
warning() << "initialisation of " << full_type.id()
<< " requires initializer list, found "
<< value.id() << " instead" << eom;

// in case of a variable-length array consume all remaining
// initializer elements
if(vla_permitted &&
dest_type.id()==ID_array &&
(to_array_type(dest_type).size().is_zero() ||
to_array_type(dest_type).size().is_nil()))
{
value.id(ID_initializer_list);
value.operands().clear();
for( ; init_it!=initializer_list.operands().end(); ++init_it)
value.copy_to_operands(*init_it);
*dest=do_initializer_rec(value, dest_type, force_constant);

return init_it;
}
else
{
err_location(value);
error() << "cannot initialize type `"
<< to_string(dest_type) << "' using value `"
<< to_string(value) << "'" << eom;
throw 0;
}
}

dest=&(dest->op0());

// we run into another loop iteration
}

return ++init_it;
}

void c_typecheck_baset::increment_designator(designatort &designator)
Expand Down Expand Up @@ -651,8 +685,7 @@ designatort c_typecheck_baset::make_designator(
forall_operands(it, src)
{
const exprt &d_op=*it;
designatort::entryt entry;
entry.type=type;
designatort::entryt entry(type);
const typet &full_type=follow(entry.type);

if(full_type.id()==ID_array)
Expand Down Expand Up @@ -856,10 +889,12 @@ exprt c_typecheck_baset::do_initializer_list(

designator_enter(type, current_designator);

forall_operands(it, value)
const exprt::operandst &operands=value.operands();
for(exprt::operandst::const_iterator it=operands.begin();
it!=operands.end(); ) // no ++it
{
do_designated_initializer(
result, current_designator, *it, force_constant);
it=do_designated_initializer(
result, current_designator, value, it, force_constant);

// increase designator -- might go up
increment_designator(current_designator);
Expand Down
4 changes: 3 additions & 1 deletion src/ansi-c/designator.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ class designatort
{
size_t index;
size_t size;
bool vla_permitted;
typet type, subtype;

entryt():index(0), size(0)
explicit entryt(const typet &type):
index(0), size(0), vla_permitted(false), type(type)
{
}
};
Expand Down

0 comments on commit 9740142

Please sign in to comment.