[vm/ffi] Add fields to `Struct`s which should not be empty

This CL adds fields to `Struct`s which should not be empty or removes
the structs.

Issue: https://github.com/dart-lang/sdk/issues/44622
Issue: https://github.com/dart-lang/sdk/issues/43974

TEST=tests/ffi/vmspecific_static_checks_test.dart

Change-Id: I4a684bd96e3ed16a3fd0dd17019aeabf64ef074a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/179182
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/pkg/analyzer/test/src/diagnostics/field_in_struct_with_initializer_test.dart b/pkg/analyzer/test/src/diagnostics/field_in_struct_with_initializer_test.dart
index da75f22..9c908b5 100644
--- a/pkg/analyzer/test/src/diagnostics/field_in_struct_with_initializer_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/field_in_struct_with_initializer_test.dart
@@ -39,6 +39,7 @@
     await assertNoErrorsInCode(r'''
 import 'dart:ffi';
 class C extends Struct {
+  Pointer p;
   static String str = '';
 }
 ''');
diff --git a/pkg/analyzer/test/src/diagnostics/generic_struct_subclass_test.dart b/pkg/analyzer/test/src/diagnostics/generic_struct_subclass_test.dart
index 8b4aef4..710a812 100644
--- a/pkg/analyzer/test/src/diagnostics/generic_struct_subclass_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/generic_struct_subclass_test.dart
@@ -18,7 +18,9 @@
   test_genericStruct() async {
     await assertErrorsInCode(r'''
 import 'dart:ffi';
-class S<T> extends Struct {}
+class S<T> extends Struct {
+  Pointer notEmpty;
+}
 ''', [
       error(FfiCode.GENERIC_STRUCT_SUBCLASS, 25, 1),
     ]);
@@ -27,7 +29,9 @@
   test_validStruct() async {
     await assertNoErrorsInCode(r'''
 import 'dart:ffi';
-class S extends Struct {}
+class S extends Struct {
+  Pointer notEmpty;
+}
 ''');
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_field_type_in_struct_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_field_type_in_struct_test.dart
index 06cd7f3..6fec555 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_field_type_in_struct_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_field_type_in_struct_test.dart
@@ -15,11 +15,14 @@
 
 @reflectiveTest
 class InvalidFieldTypeInStructTest extends PubPackageResolutionTest {
+  // TODO(https://dartbug.com/44677): Remove Pointer notEmpty field.
   test_instance_invalid() async {
     await assertErrorsInCode(r'''
 import 'dart:ffi';
 class C extends Struct {
   String str;
+
+  Pointer notEmpty;
 }
 ''', [
       error(FfiCode.INVALID_FIELD_TYPE_IN_STRUCT, 46, 6),
@@ -35,11 +38,14 @@
 ''');
   }
 
+  // TODO(https://dartbug.com/44677): Remove Pointer notEmpty field.
   test_static() async {
     await assertNoErrorsInCode(r'''
 import 'dart:ffi';
 class C extends Struct {
   static String str;
+
+  Pointer notEmpty;
 }
 ''');
   }
diff --git a/pkg/analyzer/test/src/diagnostics/missing_field_type_in_struct_test.dart b/pkg/analyzer/test/src/diagnostics/missing_field_type_in_struct_test.dart
index cfae21f..c5ae82c 100644
--- a/pkg/analyzer/test/src/diagnostics/missing_field_type_in_struct_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/missing_field_type_in_struct_test.dart
@@ -20,6 +20,8 @@
 import 'dart:ffi';
 class C extends Struct {
   var str;
+
+  Pointer notEmpty;
 }
 ''', [
       error(FfiCode.MISSING_FIELD_TYPE_IN_STRUCT, 50, 3),
diff --git a/pkg/analyzer/test/src/diagnostics/subtype_of_ffi_class_test.dart b/pkg/analyzer/test/src/diagnostics/subtype_of_ffi_class_test.dart
index a5aed99..7073a39 100644
--- a/pkg/analyzer/test/src/diagnostics/subtype_of_ffi_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/subtype_of_ffi_class_test.dart
@@ -84,7 +84,9 @@
   test_Struct() async {
     await assertNoErrorsInCode(r'''
 import 'dart:ffi';
-class C extends Struct {}
+class C extends Struct {
+  Pointer notEmpty;
+}
 ''');
   }
 
diff --git a/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart b/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart
index 66f4192..d5ca275 100644
--- a/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart
@@ -21,10 +21,12 @@
   test_extends() async {
     await assertErrorsInCode(r'''
 import 'dart:ffi';
-class S extends Struct {}
+class S extends Struct {
+  Pointer notEmpty;
+}
 class C extends S {}
 ''', [
-      error(FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS, 61, 1),
+      error(FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS, 82, 1),
     ]);
   }
 }
diff --git a/runtime/bin/ffi_test/ffi_test_functions_generated.cc b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
index a77bff1..65d06a5 100644
--- a/runtime/bin/ffi_test/ffi_test_functions_generated.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
@@ -34,8 +34,6 @@
   CHECK(((EXPECTED * 0.99) <= (ACTUAL) && (EXPECTED * 1.01) >= (ACTUAL)) ||    \
         ((EXPECTED * 0.99) >= (ACTUAL) && (EXPECTED * 1.01) <= (ACTUAL)))
 
-struct Struct0Bytes {};
-
 struct Struct1ByteInt {
   int8_t a0;
 };
diff --git a/tests/ffi/function_structs_by_value_generated_test.dart b/tests/ffi/function_structs_by_value_generated_test.dart
index c8b91cb..ba98841 100644
--- a/tests/ffi/function_structs_by_value_generated_test.dart
+++ b/tests/ffi/function_structs_by_value_generated_test.dart
@@ -106,10 +106,6 @@
   }
 }
 
-class Struct0Bytes extends Struct {
-  String toString() => "()";
-}
-
 class Struct1ByteInt extends Struct {
   @Int8()
   external int a0;
diff --git a/tests/ffi/generator/structs_by_value_tests_configuration.dart b/tests/ffi/generator/structs_by_value_tests_configuration.dart
index 718caea..bc1b8a1 100644
--- a/tests/ffi/generator/structs_by_value_tests_configuration.dart
+++ b/tests/ffi/generator/structs_by_value_tests_configuration.dart
@@ -421,7 +421,6 @@
 ];
 
 final structs = [
-  struct0bytes,
   struct1byteInt,
   struct3bytesInt,
   struct3bytesInt2,
@@ -462,9 +461,6 @@
   structNestedEvenBigger,
 ];
 
-/// Using empty structs is undefined behavior in C.
-final struct0bytes = StructType([]);
-
 final struct1byteInt = StructType([int8]);
 final struct3bytesInt = StructType(List.filled(3, uint8));
 final struct3bytesInt2 = StructType.disambiguate([int16, int8], "2ByteAligned");
diff --git a/tests/ffi/regress_43016_test.dart b/tests/ffi/regress_43016_test.dart
index f1489e0..db3d816 100644
--- a/tests/ffi/regress_43016_test.dart
+++ b/tests/ffi/regress_43016_test.dart
@@ -10,7 +10,10 @@
 
 import 'dylib_utils.dart';
 
-class MyStruct extends Struct {}
+class MyStruct extends Struct {
+  @Int8()
+  external int a;
+}
 
 typedef _c_pass_struct = Int32 Function(Pointer<MyStruct>);
 
diff --git a/tests/ffi/vmspecific_regress_38993_test.dart b/tests/ffi/vmspecific_regress_38993_test.dart
index 8c9972f..4391b00 100644
--- a/tests/ffi/vmspecific_regress_38993_test.dart
+++ b/tests/ffi/vmspecific_regress_38993_test.dart
@@ -8,6 +8,8 @@
 
 class C extends Struct {
   dynamic x; //# 1: compile-time error
+
+  external Pointer notEmpty;
 }
 
 main() {}
diff --git a/tests/ffi/vmspecific_static_checks_test.dart b/tests/ffi/vmspecific_static_checks_test.dart
index cbce8e6..ff194bd 100644
--- a/tests/ffi/vmspecific_static_checks_test.dart
+++ b/tests/ffi/vmspecific_static_checks_test.dart
@@ -358,24 +358,32 @@
 class TestStruct5 extends Struct {
   @Int64() //# 54: compile-time error
   external double z; //# 54: compile-time error
+
+  external Pointer notEmpty;
 }
 
 // error on annotation not matching up
 class TestStruct6 extends Struct {
   @Void() //# 55: compile-time error
   external double z; //# 55: compile-time error
+
+  external Pointer notEmpty;
 }
 
 // error on annotation not matching up
 class TestStruct7 extends Struct {
   @NativeType() //# 56: compile-time error
   external double z; //# 56: compile-time error
+
+  external Pointer notEmpty;
 }
 
 // error on field initializer on field
 class TestStruct8 extends Struct {
   @Double() //# 57: compile-time error
   double z = 10.0; //# 57: compile-time error
+
+  external Pointer notEmpty;
 }
 
 // error on field initializer in constructor
@@ -383,6 +391,8 @@
   @Double() //# 58: compile-time error
   double z; //# 58: compile-time error
 
+  external Pointer notEmpty;
+
   TestStruct9() : z = 0.0 {} //# 58: compile-time error
 }
 
@@ -395,6 +405,8 @@
 class TestStruct12 extends Struct {
   @Pointer //# 61: compile-time error
   external TestStruct9 struct; //# 61: compile-time error
+
+  external Pointer notEmpty;
 }
 
 class DummyAnnotation {
@@ -500,12 +512,16 @@
 }
 
 class TestStruct1001 extends Struct {
-  Handle handle; //# 1001: compile-time error
+  external Handle handle; //# 1001: compile-time error
+
+  external Pointer notEmpty;
 }
 
 class TestStruct1002 extends Struct {
   @Handle() //# 1002: compile-time error
-  Object handle; //# 1002: compile-time error
+  external Object handle; //# 1002: compile-time error
+
+  external Pointer notEmpty;
 }
 
 class EmptyStruct extends Struct {}
@@ -554,6 +570,8 @@
 
 class HasNestedEmptyStruct extends Struct {
   external EmptyStruct nestedEmptyStruct; //# 1106: compile-time error
+
+  external Pointer notEmpty;
 }
 
 void testAllocateGeneric() {
diff --git a/tests/ffi_2/function_structs_by_value_generated_test.dart b/tests/ffi_2/function_structs_by_value_generated_test.dart
index e00f3fa..6867406 100644
--- a/tests/ffi_2/function_structs_by_value_generated_test.dart
+++ b/tests/ffi_2/function_structs_by_value_generated_test.dart
@@ -106,10 +106,6 @@
   }
 }
 
-class Struct0Bytes extends Struct {
-  String toString() => "()";
-}
-
 class Struct1ByteInt extends Struct {
   @Int8()
   int a0;
diff --git a/tests/ffi_2/generator/structs_by_value_tests_configuration.dart b/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
index 718caea..bc1b8a1 100644
--- a/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
+++ b/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
@@ -421,7 +421,6 @@
 ];
 
 final structs = [
-  struct0bytes,
   struct1byteInt,
   struct3bytesInt,
   struct3bytesInt2,
@@ -462,9 +461,6 @@
   structNestedEvenBigger,
 ];
 
-/// Using empty structs is undefined behavior in C.
-final struct0bytes = StructType([]);
-
 final struct1byteInt = StructType([int8]);
 final struct3bytesInt = StructType(List.filled(3, uint8));
 final struct3bytesInt2 = StructType.disambiguate([int16, int8], "2ByteAligned");
diff --git a/tests/ffi_2/regress_43016_test.dart b/tests/ffi_2/regress_43016_test.dart
index b0ebc0c..997e451 100644
--- a/tests/ffi_2/regress_43016_test.dart
+++ b/tests/ffi_2/regress_43016_test.dart
@@ -10,7 +10,10 @@
 
 import 'dylib_utils.dart';
 
-class MyStruct extends Struct {}
+class MyStruct extends Struct {
+  @Int8()
+  int a;
+}
 
 typedef _c_pass_struct = Int32 Function(Pointer<MyStruct> arg0);
 
diff --git a/tests/ffi_2/vmspecific_regress_38993_test.dart b/tests/ffi_2/vmspecific_regress_38993_test.dart
index 8c9972f..e7c4315 100644
--- a/tests/ffi_2/vmspecific_regress_38993_test.dart
+++ b/tests/ffi_2/vmspecific_regress_38993_test.dart
@@ -8,6 +8,8 @@
 
 class C extends Struct {
   dynamic x; //# 1: compile-time error
+
+  Pointer notEmpty;
 }
 
 main() {}
diff --git a/tests/ffi_2/vmspecific_static_checks_test.dart b/tests/ffi_2/vmspecific_static_checks_test.dart
index f1db86e..8883658 100644
--- a/tests/ffi_2/vmspecific_static_checks_test.dart
+++ b/tests/ffi_2/vmspecific_static_checks_test.dart
@@ -358,24 +358,32 @@
 class TestStruct5 extends Struct {
   @Int64() //# 54: compile-time error
   double z; //# 54: compile-time error
+
+  Pointer notEmpty;
 }
 
 // error on annotation not matching up
 class TestStruct6 extends Struct {
   @Void() //# 55: compile-time error
   double z; //# 55: compile-time error
+
+  Pointer notEmpty;
 }
 
 // error on annotation not matching up
 class TestStruct7 extends Struct {
   @NativeType() //# 56: compile-time error
   double z; //# 56: compile-time error
+
+  Pointer notEmpty;
 }
 
 // error on field initializer on field
 class TestStruct8 extends Struct {
   @Double() //# 57: compile-time error
   double z = 10.0; //# 57: compile-time error
+
+  Pointer notEmpty;
 }
 
 // error on field initializer in constructor
@@ -395,6 +403,8 @@
 class TestStruct12 extends Struct {
   @Pointer //# 61: compile-time error
   TestStruct9 struct; //# 61: compile-time error
+
+  Pointer notEmpty;
 }
 
 class DummyAnnotation {
@@ -501,11 +511,15 @@
 
 class TestStruct1001 extends Struct {
   Handle handle; //# 1001: compile-time error
+
+  Pointer notEmpty;
 }
 
 class TestStruct1002 extends Struct {
   @Handle() //# 1002: compile-time error
   Object handle; //# 1002: compile-time error
+
+  Pointer notEmpty;
 }
 
 class EmptyStruct extends Struct {}
@@ -554,6 +568,8 @@
 
 class HasNestedEmptyStruct extends Struct {
   EmptyStruct nestedEmptyStruct; //# 1106: compile-time error
+
+  Pointer notEmpty;
 }
 
 void testAllocateGeneric() {