Handle array initialization with a non-array gracefully
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).
This commit is contained in:
parent
13a75381a0
commit
9740142bed
|
@ -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));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
KNOWNBUG
|
||||
CORE
|
||||
main.c
|
||||
|
||||
^EXIT=0$
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
}
|
|
@ -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
|
|
@ -89,10 +89,11 @@ protected:
|
|||
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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -562,7 +568,7 @@ void c_typecheck_baset::do_designated_initializer(
|
|||
full_type.id()==ID_vector)
|
||||
{
|
||||
*dest=value;
|
||||
return; // done
|
||||
return ++init_it; // done
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
|
|
@ -24,9 +24,11 @@ public:
|
|||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue