diff --git a/regression/ansi-c/Struct_Initialization1/main.c b/regression/ansi-c/Struct_Initialization1/main.c index b497a0b60dd..f2e75463d6c 100644 --- a/regression/ansi-c/Struct_Initialization1/main.c +++ b/regression/ansi-c/Struct_Initialization1/main.c @@ -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)); diff --git a/regression/ansi-c/Struct_Initialization1/test.desc b/regression/ansi-c/Struct_Initialization1/test.desc index fc2b1874059..466da18b2b5 100644 --- a/regression/ansi-c/Struct_Initialization1/test.desc +++ b/regression/ansi-c/Struct_Initialization1/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c ^EXIT=0$ diff --git a/regression/ansi-c/Struct_Initialization2/main.c b/regression/ansi-c/Struct_Initialization2/main.c new file mode 100644 index 00000000000..98cce21ebc8 --- /dev/null +++ b/regression/ansi-c/Struct_Initialization2/main.c @@ -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() +{ +} diff --git a/regression/ansi-c/Struct_Initialization2/test.desc b/regression/ansi-c/Struct_Initialization2/test.desc new file mode 100644 index 00000000000..73c2caa52cd --- /dev/null +++ b/regression/ansi-c/Struct_Initialization2/test.desc @@ -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 diff --git a/src/ansi-c/c_typecheck_base.h b/src/ansi-c/c_typecheck_base.h index 521ae29aa4a..eec934736d5 100644 --- a/src/ansi-c/c_typecheck_base.h +++ b/src/ansi-c/c_typecheck_base.h @@ -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); diff --git a/src/ansi-c/c_typecheck_initializer.cpp b/src/ansi-c/c_typecheck_initializer.cpp index fd098259796..1bc494c8d4a 100644 --- a/src/ansi-c/c_typecheck_initializer.cpp +++ b/src/ansi-c/c_typecheck_initializer.cpp @@ -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); diff --git a/src/ansi-c/designator.h b/src/ansi-c/designator.h index d31d3bb3e66..957bbbb6821 100644 --- a/src/ansi-c/designator.h +++ b/src/ansi-c/designator.h @@ -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) { } };