runtime: synchronize empty struct field handling

In GCCGO and gollvm, the logic for allocating one byte for the last field is:
1. the last field has zero size
2. the struct itself does not have zero size
3. the last field is not blank
this commit adds the last two conditions to runtime.structToFFI.

For golang/go#55146

Change-Id: Iabc3ee09e7f14fab037fd197a9658b099c419904
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/431735
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
diff --git a/libgo/go/runtime/ffi.go b/libgo/go/runtime/ffi.go
index cd8479e..86ce5b8 100644
--- a/libgo/go/runtime/ffi.go
+++ b/libgo/go/runtime/ffi.go
@@ -4,6 +4,7 @@
 
 // Only build this file if libffi is supported.
 
+//go:build libffi
 // +build libffi
 
 package runtime
@@ -221,9 +222,6 @@
 // structToFFI returns an ffi_type for a Go struct type.
 func structToFFI(typ *structtype) *__ffi_type {
 	c := len(typ.fields)
-	if c == 0 {
-		return emptyStructToFFI()
-	}
 	if typ.typ.kind&kindDirectIface != 0 {
 		return ffi_type_pointer()
 	}
@@ -231,6 +229,7 @@
 	fields := make([]*__ffi_type, 0, c+1)
 	checkPad := false
 	lastzero := false
+	sawnonzero := false
 	for i, v := range typ.fields {
 		// Skip zero-sized fields; they confuse libffi,
 		// and there is no value to pass in any case.
@@ -239,10 +238,13 @@
 		// next field.
 		if v.typ.size == 0 {
 			checkPad = true
-			lastzero = true
+			if v.name == nil || *v.name != "_" {
+				lastzero = true
+			}
 			continue
 		}
 		lastzero = false
+		sawnonzero = true
 
 		if checkPad {
 			off := uintptr(0)
@@ -263,6 +265,10 @@
 		fields = append(fields, typeToFFI(v.typ))
 	}
 
+	if !sawnonzero {
+		return emptyStructToFFI()
+	}
+
 	if lastzero {
 		// The compiler adds one byte padding to non-empty struct ending
 		// with a zero-sized field (types.cc:get_backend_struct_fields).