This patch to the Go frontend avoids padding zero-sized trailing fields in the struct created to hold result parameters. This avoids a miscompilation when a function returns multiple results and the last result is zero-sized (this is not a useful way to write a function but it can happen reasonably if on some targets the last result does have a size). Nothing can take the address of a field in a result struct, so the padding is not required. This fixes GCC PR 101994. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline.
Ian
0d3eabf88aa766056f3e0061a7d369368629a451 diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index ff41af787b1..f4816816500 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -21b30eddc59d92a07264c3b21eb032d6c303d16f +c11d9f8275f2bbe9b05cdd815c79ac331f78e15c The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index e76600daab9..cd692506efc 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -5050,6 +5050,7 @@ Function_type::get_backend_fntype(Gogo* gogo) Struct_type* st = Type::make_struct_type(sfl, this->location()); st->set_is_struct_incomparable(); + st->set_is_results_struct(); ins.first->second = st->get_backend(gogo); } bresult_struct = ins.first->second; @@ -6458,7 +6459,7 @@ get_backend_struct_fields(Gogo* gogo, Struct_type* type, bool use_placeholder, saw_nonzero = true; } go_assert(i == fields->size()); - if (saw_nonzero && lastsize == 0) + if (saw_nonzero && lastsize == 0 && !type->is_results_struct()) { // For nonzero-sized structs which end in a zero-sized thing, we add // an extra byte of padding to the type. This padding ensures that diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index ca1ab49c57e..0c5180668ea 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -2501,7 +2501,8 @@ class Struct_type : public Type Struct_type(Struct_field_list* fields, Location location) : Type(TYPE_STRUCT), fields_(fields), location_(location), all_methods_(NULL), - is_struct_incomparable_(false), has_padding_(false) + is_struct_incomparable_(false), has_padding_(false), + is_results_struct_(false) { } // Return the field NAME. This only looks at local fields, not at @@ -2632,6 +2633,17 @@ class Struct_type : public Type set_has_padding() { this->has_padding_ = true; } + // Return whether this is a results struct created to hold the + // results of a function that returns multiple results. + bool + is_results_struct() const + { return this->is_results_struct_; } + + // Record that this is a results struct. + void + set_is_results_struct() + { this->is_results_struct_ = true; } + // Write the hash function for this type. void write_hash_function(Gogo*, Function_type*); @@ -2742,6 +2754,9 @@ class Struct_type : public Type // True if this struct's backend type has padding, due to trailing // zero-sized field. bool has_padding_; + // True if this is a results struct created to hold the results of a + // function that returns multiple results. + bool is_results_struct_; }; // The type of an array.