diff --git a/tools/fidl/gidl-conformance-suite/conformance.gidl b/tools/fidl/gidl-conformance-suite/conformance.gidl
new file mode 100644
index 0000000000000000000000000000000000000000..6aae4d1326de55f023a776214d8a5c4555cb0735
--- /dev/null
+++ b/tools/fidl/gidl-conformance-suite/conformance.gidl
@@ -0,0 +1,403 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+success("EmptyStruct") {
+	value = EmptyStruct {
+	}
+	bytes = {
+		0x00, // one byte
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding
+	}
+}
+
+success("EmptyStructSandwich") {
+	value = EmptyStructSandwich {
+		before: "before",
+		es: EmptyStruct {},
+		after: "after",
+	}
+	bytes = {
+		6, 0, 0, 0, 0, 0, 0, 0, // length of "before"
+		255, 255, 255, 255, 255, 255, 255, 255, // "before" is present
+		0,                   // empty struct zero field
+		0, 0, 0, 0, 0, 0, 0, // 7 bytes of padding after empty struct, to align to 64 bits
+		5, 0, 0, 0, 0, 0, 0, 0, // length of "after"
+		255, 255, 255, 255, 255, 255, 255, 255, // "after" is present
+		'b', 'e', 'f', 'o', 'r', 'e',
+		0, 0, // 2 bytes of padding after "before", to align to 64 bits
+		'a', 'f', 't', 'e', 'r', // "after" string
+		0, 0, 0, // 3 bytes of padding after "after", to align to 64 bits
+	}
+}
+
+success("Uint8Uint16Uint32Uint64") {
+	value = Uint8Uint16Uint32Uint64 {
+		f1: 0x01,
+		f2: 0x0203,
+		f3: 0x04050607,
+		f4: 0x08090a0b0c0d0e0f,
+	}
+	bytes = {
+		0x01, // f1
+		0x00, // padding
+		0x03, 0x02, // f2
+		0x07, 0x06, 0x05, 0x04, // f3
+		0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, // f4
+	}
+}
+
+success("Uint64Uint32Uint16Uint8") {
+	value = Uint64Uint32Uint16Uint8 {
+		f1: 0x08090a0b0c0d0e0f,
+		f2: 0x04050607,
+		f3: 0x0203,
+		f4: 0x01,
+	}
+	bytes = {
+		0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, // f1
+		0x07, 0x06, 0x05, 0x04, // f2
+		0x03, 0x02, // f3
+		0x01, // f4
+		0x00, // padding
+	}
+}
+
+success("SimpleTableEmpty") {
+	value = StructOfSimpleTable {
+		table: SimpleTable {},
+	}
+	bytes = {
+		0, 0, 0, 0, 0, 0, 0, 0, // max ordinal
+		255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+	}
+}
+
+success("SimpleTableXAndY") {
+	value = StructOfSimpleTable {
+		table: SimpleTable {
+			x: 42,
+			y: 67,
+		},
+	}
+	bytes = {
+		5, 0, 0, 0, 0, 0, 0, 0, // max ordinal
+		255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+		8, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles
+		255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+		0, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles
+		0, 0, 0, 0, 0, 0, 0, 0, // no alloc
+		0, 0, 0, 0, 0, 0, 0, 0, // envelope 3: num bytes / num handles
+		0, 0, 0, 0, 0, 0, 0, 0, // no alloc
+		0, 0, 0, 0, 0, 0, 0, 0, // envelope 4: num bytes / num handles
+		0, 0, 0, 0, 0, 0, 0, 0, // no alloc
+		8, 0, 0, 0, 0, 0, 0, 0, // envelope 5: num bytes / num handles
+		255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+		42, 0, 0, 0, 0, 0, 0, 0, // field X
+		67, 0, 0, 0, 0, 0, 0, 0, // field Y
+	}
+}
+
+success("SimpleTableJustY") {
+	value = StructOfSimpleTable {
+		table: SimpleTable {
+			y: 67,
+		},
+	}
+	bytes = {
+		5, 0, 0, 0, 0, 0, 0, 0, // max ordinal
+		255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+		0, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles
+		0, 0, 0, 0, 0, 0, 0, 0, // no alloc
+		0, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles
+		0, 0, 0, 0, 0, 0, 0, 0, // no alloc
+		0, 0, 0, 0, 0, 0, 0, 0, // envelope 3: num bytes / num handles
+		0, 0, 0, 0, 0, 0, 0, 0, // no alloc
+		0, 0, 0, 0, 0, 0, 0, 0, // envelope 4: num bytes / num handles
+		0, 0, 0, 0, 0, 0, 0, 0, // no alloc
+		8, 0, 0, 0, 0, 0, 0, 0, // envelope 5: num bytes / num handles
+		255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+		67, 0, 0, 0, 0, 0, 0, 0, // field Y
+	}
+}
+
+success("TableWithStringAndVectorNoVectorContent") {
+	value = StructOfTableWithStringAndVector {
+		table: TableWithStringAndVector {
+			foo: "hello",
+			bar: 27,
+		},
+	}
+	bytes = {
+		2, 0, 0, 0, 0, 0, 0, 0, // max ordinal
+		255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+		24, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles
+		255, 255, 255, 255, 255, 255, 255, 255, // envelope 1: alloc present
+		8, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles
+		255, 255, 255, 255, 255, 255, 255, 255, // envelope 2: alloc present
+		5, 0, 0, 0, 0, 0, 0, 0, // element 1: length
+		255, 255, 255, 255, 255, 255, 255, 255, // element 1: alloc present
+		104, 101, 108, 108, 111, 0, 0, 0, // element 1: hello
+		27, 0, 0, 0, 0, 0, 0, 0, // element 2: value
+	}
+}
+
+// TODO(FIDL-626): Create test with TableWithStringAndVectorHasVectorContent.
+
+success("SimpleTableThenUint64") {
+	value = SimpleTableThenUint64 {
+		table: SimpleTable {
+			x: 42,
+			y: 67,
+		},
+		number: 0xdeadbeefdeadbeef,
+	}
+	bytes = {
+		5, 0, 0, 0, 0, 0, 0, 0, // max ordinal
+		255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+		0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, // uint64 number
+		8, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles
+		255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+		0, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles
+		0, 0, 0, 0, 0, 0, 0, 0, // no alloc
+		0, 0, 0, 0, 0, 0, 0, 0, // envelope 3: num bytes / num handles
+		0, 0, 0, 0, 0, 0, 0, 0, // no alloc
+		0, 0, 0, 0, 0, 0, 0, 0, // envelope 4: num bytes / num handles
+		0, 0, 0, 0, 0, 0, 0, 0, // no alloc
+		8, 0, 0, 0, 0, 0, 0, 0, // envelope 5: num bytes / num handles
+		255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+		42, 0, 0, 0, 0, 0, 0, 0, // field X
+		67, 0, 0, 0, 0, 0, 0, 0, // field Y
+	}
+}
+
+success("InlineXunionInStruct") {
+	value = TestInlineXUnionInStruct {
+		before: "before",
+		xu: SampleXUnion {
+			u: 0xdeadbeef,
+		},
+		after: "after",
+	}
+	bytes = {
+		0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence
+
+		0xb2, 0x56, 0x9c, 0x38, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
+		0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
+
+		0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence
+
+		// secondary object 1: "before"
+		'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00,
+
+		// secondary object 2: xunion content
+		0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, // xunion envelope content (0xdeadbeef) + padding
+
+		// secondary object 3: "after"
+		'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00,
+	}
+}
+
+success("OptionalXunionInStructAbsent") {
+	value = TestOptionalXUnionInStruct {
+		before: "before",
+		// no SampleXUnion
+		after: "after",
+	}
+	bytes = {
+		0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence
+
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // envelope data is absent
+
+		0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence
+
+		// secondary object 1: "before"
+		'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00,
+
+		// secondary object 2: "after"
+		'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00,
+	}
+}
+
+success("OptionalXunionInStructAbsent") {
+	value = TestOptionalXUnionInStruct {
+		before: "before",
+		xu: SampleXUnion {
+			u: 0xdeadbeef,
+		},
+		after: "after",
+	}
+	bytes = {
+		0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence
+
+		0xb2, 0x56, 0x9c, 0x38, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
+		0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
+
+		0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "after" presence
+
+		// secondary object 1: "before"
+		'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00,
+
+		// secondary object 2: xunion content
+		0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, // xunion envelope content (0xdeadbeef) + padding
+
+		// secondary object 3: "after"
+		'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00,
+	}
+}
+
+success("XunionInTableXunionAbsent") {
+	value = TestXUnionInTable {
+		value: XUnionInTable {
+			before: "before",
+			// no SampleXUnion
+			after: "after",
+		},
+	}
+	bytes = {
+		// primary object
+		0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // vector<envelope> element count
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // vector<envelope> present
+
+		// secondary object 1: vector data
+		// vector[0]: envelope<string before>
+		0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" is present
+		// vector[1]: envelope<SampleXUnion xu>
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xunion is absent
+		// vector[2]: envelope<string after>
+		0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "after" is present
+
+		// secondary object 2: "before" length + pointer
+		0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" present
+
+		// secondary object 3: "before"
+		'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00, // "before"
+
+		// secondary object 4: "after" length + pointer
+		0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "after" present
+
+		// secondary object 5: "before"
+		'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00, // "after"
+	}
+}
+
+success("XunionInTableXunionPresent") {
+	value = TestXUnionInTable {
+		value: XUnionInTable {
+			before: "before",
+			xu: SampleXUnion {
+				u: 0xdeadbeef,
+			},
+			after: "after",
+		},
+	}
+	bytes = {
+		// primary object
+		0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // vector<envelope> element count
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // vector<envelope> present
+
+		// secondary object 1: vector data
+		// vector[0]: envelope<string before>
+		0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" is present
+		// vector[1]: envelope<SampleXUnion xu>
+		0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // xunion is present
+		// vector[2]: envelope<string after>
+		0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "after" is present
+
+		// secondary object 2: "before" length + pointer
+		0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" present
+
+		// secondary object 3: "before"
+		'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00, // "before"
+
+		// secondary object 4: xunion
+		0xb2, 0x56, 0x9c, 0x38, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
+		0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
+
+		// secondary object 5: xunion content
+		0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, // 0xdeadbeef + padding
+
+		// secondary object 6: "after" length + pointer
+		0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "after" present
+
+		// secondary object 7: "before"
+		'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00, // "after"
+	}
+}
+
+success("AddEthernetDeviceRequest") {
+	value = TestAddEthernetDeviceRequest {
+		topological_path: "@/dev/sys/pci/00:03.0/e1000/ethernet",
+		config: InterfaceConfig {
+			name: "ethp0003",
+			ip_address_config: IpAddressConfig {
+				dhcp: true,
+			},
+		},
+		// TODO(FIDL-625): This should be a handle.
+		this_should_be_a_handle: 0xffffffff,
+	}
+	bytes = {
+		0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // topological_path
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // topological_path
+		0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // name
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // name
+		0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // subnet (dhcp variant)
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding
+		0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // device (handle present)
+		0x40, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x73, 0x79, // @/dev/sy
+		0x73, 0x2f, 0x70, 0x63, 0x69, 0x2f, 0x30, 0x30, // s/pci/00
+		0x3a, 0x30, 0x33, 0x2e, 0x30, 0x2f, 0x65, 0x31, // :03.0/e1
+		0x30, 0x30, 0x30, 0x2f, 0x65, 0x74, 0x68, 0x65, // 000/ethe
+		0x72, 0x6e, 0x65, 0x74, 0x00, 0x00, 0x00, 0x00, // rnet
+		0x65, 0x74, 0x68, 0x70, 0x30, 0x30, 0x30, 0x33, // ethp0003
+	}
+}
+
+success("FileGetAttrResponse") {
+	value = FileGetAttrResponse {
+		s: 0x7eadbeaf,
+		attributes: NodeAttributes {
+			mode: 0x962381a4,
+			id: 1,
+			content_size: 231,
+			storage_size: 231,
+			link_count: 1,
+			creation_time: 0x8877665544332211,
+			modification_time: 0x00ffeeddccbbaa99,
+		},
+	}
+	bytes = {
+		0xaf, 0xbe, 0xad, 0x7e, 0x00, 0x00, 0x00, 0x00,
+		0xa4, 0x81, 0x23, 0x96, 0x00, 0x00, 0x00, 0x00,
+		1, 0, 0, 0, 0, 0, 0, 0,
+		231, 0, 0, 0, 0, 0, 0, 0,
+		231, 0, 0, 0, 0, 0, 0, 0,
+		1, 0, 0, 0, 0, 0, 0, 0,
+		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+		0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00,
+	}
+}
diff --git a/tools/fidl/gidl-conformance-suite/mix_and_match.test.fidl b/tools/fidl/gidl-conformance-suite/mix_and_match.test.fidl
new file mode 100644
index 0000000000000000000000000000000000000000..fdf8032d2167a4ab78c588af105292b5a18f8176
--- /dev/null
+++ b/tools/fidl/gidl-conformance-suite/mix_and_match.test.fidl
@@ -0,0 +1,51 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library conformance;
+
+using zx;
+
+table XUnionInTable {
+    1: string before;
+    2: SampleXUnion xu;
+    3: string after;
+};
+
+struct TestXUnionInTable {
+    XUnionInTable value;
+};
+
+protocol EthernetDevice {};
+
+union IpAddressConfig {
+    array<uint32>:6 padding_size_24_align_4;
+    bool dhcp;
+};
+
+struct InterfaceConfig {
+    string name;
+    IpAddressConfig ip_address_config;
+};
+
+struct TestAddEthernetDeviceRequest {
+    string topological_path;
+    InterfaceConfig config;
+    // TODO(FIDL-625): Use 'EthernetDevice device;' instead.
+    uint32 this_should_be_a_handle;
+};
+
+struct NodeAttributes {
+    uint32 mode;
+    uint64 id;
+    uint64 content_size;
+    uint64 storage_size;
+    uint64 link_count;
+    uint64 creation_time;
+    uint64 modification_time;
+};
+
+struct FileGetAttrResponse {
+    zx.status s;
+    NodeAttributes attributes;
+};
diff --git a/tools/fidl/gidl-conformance-suite/regen.sh b/tools/fidl/gidl-conformance-suite/regen.sh
index 1ec3c08d09ce11d259acdbae941eb5d29db98ce7..bce7d895cc2b8bf884fda0d465f9a583e0a13942 100755
--- a/tools/fidl/gidl-conformance-suite/regen.sh
+++ b/tools/fidl/gidl-conformance-suite/regen.sh
@@ -2,30 +2,30 @@
 
 set -euxo pipefail
 
-if [[ ! -d "${FUCHSIA_DIR}" ]]; then
+if [[ ! -d "${FUCHSIA_BUILD_DIR}" ]]; then
   echo "FUCHSIA_DIR environment variable not a directory"
   exit 1
 fi
 
-GOFMT="${FUCHSIA_DIR}/out/x64/tools/goroot/bin/gofmt"
+GOFMT="${FUCHSIA_BUILD_DIR}/tools/goroot/bin/gofmt"
 if [ ! -x "${GOFMT}" ]; then
     echo "error: unable to find gofmt; did the path change?" 1>&2
     exit 1
 fi
 
-FIDLC="${FUCHSIA_DIR}/out/x64/host_x64/fidlc"
+FIDLC="${FUCHSIA_BUILD_DIR}/host_x64/fidlc"
 if [ ! -x "${FIDLC}" ]; then
     echo "error: fidlc missing; did you build?" 1>&2
     exit 1
 fi
 
-FIDLGEN="${FUCHSIA_DIR}/out/x64/host_x64/fidlgen"
+FIDLGEN="${FUCHSIA_BUILD_DIR}/host_x64/fidlgen"
 if [ ! -x "${FIDLGEN}" ]; then
     echo "error: fidlgen missing; did you build?" 1>&2
     exit 1
 fi
 
-GIDL="${FUCHSIA_DIR}/out/default/tools/gidl"
+GIDL="${FUCHSIA_BUILD_DIR}/tools/gidl"
 if [ ! -x "${GIDL}" ]; then
     echo "error: gidl missing; did you build?" 1>&2
     exit 1
@@ -34,24 +34,26 @@ fi
 EXAMPLE_DIR="${FUCHSIA_DIR}/tools/fidl/gidl-conformance-suite"
 GO_LIB_DIR="${FUCHSIA_DIR}/third_party/go/src/syscall/zx/fidl/conformance"
 GO_TEST_DIR="${FUCHSIA_DIR}/third_party/go/src/syscall/zx/fidl/fidl_test"
-for src_path in `find "${EXAMPLE_DIR}" -name '*.gidl'`; do
-    base=$( echo "${src_path}" | sed -e 's/\.gidl//' )
-    gidl_path="${base}.gidl"
-    fidl_path="${base}.test.fidl"
-    tmpout=$( mktemp -d 2>/dev/null || mktemp -d -t 'tmpout' )
-    json_path=$( mktemp ${tmpout}/tmp.XXXXXXXX )
-
-    # need to have all .fidl files in one conformance library
-    ${FIDLC} \
-        --json "${json_path}" \
-        --files "${fidl_path}"
-
-    ${FIDLGEN} \
-        --generators go \
-        --json "${json_path}" \
-        --output-base "${tmpout}" \
-        --include-base "${tmpout}"
-    cat << EOF > "${GO_LIB_DIR}/impl.go"
+
+# TODO(FIDL-621): Support multiple .gidl sources.
+gidl_path="${EXAMPLE_DIR}/conformance.gidl"
+
+tmpout=$( mktemp -d 2>/dev/null || mktemp -d -t 'tmpout' )
+trap "rm -rf ${tmpout}" EXIT
+json_path=$( mktemp ${tmpout}/tmp.XXXXXXXX )
+fidlc_args="--json ${json_path} --files "
+for fidl_path in `find "${EXAMPLE_DIR}" -name '*.fidl'`; do
+    fidlc_args="${fidlc_args} ${fidl_path}"
+done
+
+${FIDLC} ${fidlc_args}
+
+${FIDLGEN} \
+    --generators go \
+    --json "${json_path}" \
+    --output-base "${tmpout}" \
+    --include-base "${tmpout}"
+cat << EOF > "${GO_LIB_DIR}/impl.go"
 // Copyright 2019 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
@@ -61,10 +63,10 @@ for src_path in `find "${EXAMPLE_DIR}" -name '*.gidl'`; do
 // +build fuchsia
 
 EOF
-    cat "${tmpout}/impl.go" >> "${GO_LIB_DIR}/impl.go"
-    ${GOFMT} -s -w "${GO_LIB_DIR}/impl.go"
+cat "${tmpout}/impl.go" >> "${GO_LIB_DIR}/impl.go"
+${GOFMT} -s -w "${GO_LIB_DIR}/impl.go"
 
-    cat << EOF > "${GO_TEST_DIR}/conformance_test.go"
+cat << EOF > "${GO_TEST_DIR}/conformance_test.go"
 // Copyright 2019 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
@@ -74,7 +76,6 @@ EOF
 // +build fuchsia
 
 EOF
-    ${GIDL} \
-        --json "${json_path}" \
-        --gidl "${gidl_path}" | ${GOFMT} >> "${GO_TEST_DIR}/conformance_test.go"
-done
+${GIDL} \
+    --json "${json_path}" \
+    --gidl "${gidl_path}" | ${GOFMT} >> "${GO_TEST_DIR}/conformance_test.go"
diff --git a/tools/fidl/gidl-conformance-suite/structs.gidl b/tools/fidl/gidl-conformance-suite/structs.gidl
deleted file mode 100644
index 20879e686abe7b09de5fea0828ed54ac175d40cd..0000000000000000000000000000000000000000
--- a/tools/fidl/gidl-conformance-suite/structs.gidl
+++ /dev/null
@@ -1,24 +0,0 @@
-success("Empty") {
-	value = Empty {
-	}
-	bytes = {
-		0x00, // one byte
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding
-	}
-}
-
-success("Uint8Uint16Uint32Uint64") {
-	value = Uint8Uint16Uint32Uint64 {
-		f1: 0x01,
-		f2: 0x0203,
-		f3: 0x04050607,
-		f4: 0x08090a0b0c0d0e0f,
-	}
-	bytes = {
-		0x01, // f1
-		0x00, // padding
-		0x03, 0x02, // f2
-		0x07, 0x06, 0x05, 0x04, // f3
-		0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, // f4
-	}
-}
diff --git a/tools/fidl/gidl-conformance-suite/structs.test.fidl b/tools/fidl/gidl-conformance-suite/structs.test.fidl
index 6d2f7afc793e07e5d7b238caa45ce239391c7b94..7340b14fbd476cff06ff84c79c7085bd9e9539fb 100644
--- a/tools/fidl/gidl-conformance-suite/structs.test.fidl
+++ b/tools/fidl/gidl-conformance-suite/structs.test.fidl
@@ -1,6 +1,16 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
 library conformance;
 
-struct Empty {};
+struct EmptyStruct {};
+
+struct EmptyStructSandwich {
+    string before;
+    EmptyStruct es;
+    string after;
+};
 
 struct Uint8Uint16Uint32Uint64 {
     uint8 f1;
@@ -8,3 +18,10 @@ struct Uint8Uint16Uint32Uint64 {
     uint32 f3;
     uint64 f4;
 };
+
+struct Uint64Uint32Uint16Uint8 {
+    uint64 f1;
+    uint32 f2;
+    uint16 f3;
+    uint8 f4;
+};
diff --git a/tools/fidl/gidl-conformance-suite/tables.test.fidl b/tools/fidl/gidl-conformance-suite/tables.test.fidl
new file mode 100644
index 0000000000000000000000000000000000000000..d70b31d42fe43aa63f67f1e70323d2eec8414ac1
--- /dev/null
+++ b/tools/fidl/gidl-conformance-suite/tables.test.fidl
@@ -0,0 +1,32 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library conformance;
+
+table SimpleTable {
+    1: int64 x;
+    2: reserved;
+    3: reserved;
+    4: reserved;
+    5: int64 y;
+};
+
+struct StructOfSimpleTable {
+    SimpleTable table;
+};
+
+struct SimpleTableThenUint64 {
+    SimpleTable table;
+    uint64 number;
+};
+
+table TableWithStringAndVector {
+    1: string foo;
+    2: int32 bar;
+    3: vector<uint8> baz;
+};
+
+struct StructOfTableWithStringAndVector {
+    TableWithStringAndVector table;
+};
diff --git a/tools/fidl/gidl-conformance-suite/xunion.test.fidl b/tools/fidl/gidl-conformance-suite/xunion.test.fidl
new file mode 100644
index 0000000000000000000000000000000000000000..93f473238fc83648ead1f05964676828478ebe0a
--- /dev/null
+++ b/tools/fidl/gidl-conformance-suite/xunion.test.fidl
@@ -0,0 +1,37 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library conformance;
+
+// TODO(FIDL-622): Do not rely on unions in xunion conformance tests.
+
+struct Int64Struct {
+    int64 x;
+};
+
+union SimpleUnion {
+    int32 i32;
+    int64 i64;
+    Int64Struct s;
+    Int64Struct? os;
+    string str;
+};
+
+xunion SampleXUnion {
+    uint32 u;
+    SimpleUnion su;
+    SimpleTable st;
+};
+
+struct TestInlineXUnionInStruct {
+    string before;
+    SampleXUnion xu;
+    string after;
+};
+
+struct TestOptionalXUnionInStruct {
+    string before;
+    SampleXUnion? xu;
+    string after;
+};
diff --git a/tools/fidl/gidl/golang/golang.go b/tools/fidl/gidl/golang/golang.go
index c375fe324904ebc0c8cb075dbf2aa4097cc00224..8fb0053145390b650db511a1e4fd8985a95c7e57 100644
--- a/tools/fidl/gidl/golang/golang.go
+++ b/tools/fidl/gidl/golang/golang.go
@@ -135,6 +135,9 @@ func (b *goValueBuilder) OnStruct(value gidlir.Object, decl *gidlmixer.StructDec
 		fieldDecl, _ := decl.ForKey(key)
 		gidlmixer.Visit(b, field, fieldDecl)
 		fieldVar := b.lastVar
+		if decl.IsKeyNullable(key) {
+			fieldVar = "&" + fieldVar
+		}
 		b.Builder.WriteString(fmt.Sprintf(
 			"%s.%s = %s\n", containerVar, fidlcommon.ToUpperCamelCase(key), fieldVar))
 	}
@@ -168,3 +171,17 @@ func (b *goValueBuilder) OnXUnion(value gidlir.Object, decl *gidlmixer.XUnionDec
 	}
 	b.lastVar = containerVar
 }
+
+func (b *goValueBuilder) OnUnion(value gidlir.Object, decl *gidlmixer.UnionDecl) {
+	containerVar := b.newVar()
+	b.Builder.WriteString(fmt.Sprintf(
+		"var %s conformance.%s\n", containerVar, value.Name))
+	for key, field := range value.Fields {
+		fieldDecl, _ := decl.ForKey(key)
+		gidlmixer.Visit(b, field, fieldDecl)
+		fieldVar := b.lastVar
+		b.Builder.WriteString(fmt.Sprintf(
+			"%s.Set%s(%s)\n", containerVar, fidlcommon.ToUpperCamelCase(key), fieldVar))
+	}
+	b.lastVar = containerVar
+}
diff --git a/tools/fidl/gidl/mixer/mixer.go b/tools/fidl/gidl/mixer/mixer.go
index 5baa3ec25c2bc5a322343c78b9481249cd3abfec..33268928c19b02960c469f1884de99209f47412e 100644
--- a/tools/fidl/gidl/mixer/mixer.go
+++ b/tools/fidl/gidl/mixer/mixer.go
@@ -41,6 +41,7 @@ type ValueVisitor interface {
 	OnStruct(value gidlir.Object, decl *StructDecl)
 	OnTable(value gidlir.Object, decl *TableDecl)
 	OnXUnion(value gidlir.Object, decl *XUnionDecl)
+	OnUnion(value gidlir.Object, decl *UnionDecl)
 }
 
 // Visit is the entry point into visiting a value, it dispatches appropriately
@@ -63,6 +64,8 @@ func Visit(visitor ValueVisitor, value interface{}, decl Declaration) {
 			visitor.OnTable(value, decl)
 		case *XUnionDecl:
 			visitor.OnXUnion(value, decl)
+		case *UnionDecl:
+			visitor.OnUnion(value, decl)
 		default:
 			panic(fmt.Sprintf("not implemented: %T", decl))
 		}
@@ -150,7 +153,7 @@ func (decl *numberDecl) conforms(value interface{}) error {
 
 type stringDecl struct {
 	hasNoKey
-	bound int
+	bound *int
 }
 
 func (decl *stringDecl) conforms(value interface{}) error {
@@ -158,10 +161,13 @@ func (decl *stringDecl) conforms(value interface{}) error {
 	default:
 		return fmt.Errorf("expecting string, found %T (%s)", value, value)
 	case string:
-		if decl.bound < len(value) {
+		if decl.bound == nil {
+			return nil
+		}
+		if bound := *decl.bound; bound < len(value) {
 			return fmt.Errorf(
 				"string '%s' is over bounds, expecting %d but was %d", value,
-				decl.bound, len(value))
+				bound, len(value))
 		}
 		return nil
 	}
@@ -183,6 +189,17 @@ func (decl *StructDecl) ForKey(key string) (Declaration, bool) {
 	return nil, false
 }
 
+// IsKeyNullable indicates whether this key is optional, i.e. whether it
+// represents an optional field.
+func (decl *StructDecl) IsKeyNullable(key string) bool {
+	for _, member := range decl.Members {
+		if string(member.Name) == key {
+			return member.Type.Nullable
+		}
+	}
+	return false
+}
+
 func (decl *StructDecl) conforms(value interface{}) error {
 	switch value := value.(type) {
 	default:
@@ -266,6 +283,41 @@ func (decl XUnionDecl) conforms(untypedValue interface{}) error {
 	}
 }
 
+// UnionDecl describes a xunion declaration.
+type UnionDecl struct {
+	fidlir.Union
+	schema schema
+}
+
+// ForKey retrieves a declaration for a key.
+func (decl UnionDecl) ForKey(key string) (Declaration, bool) {
+	for _, member := range decl.Members {
+		if string(member.Name) == key {
+			return decl.schema.LookupDeclByType(member.Type)
+		}
+	}
+	return nil, false
+}
+
+func (decl UnionDecl) conforms(untypedValue interface{}) error {
+	switch value := untypedValue.(type) {
+	default:
+		return fmt.Errorf("expecting object, found %T (%v)", untypedValue, untypedValue)
+	case gidlir.Object:
+		if num := len(value.Fields); num != 1 {
+			return fmt.Errorf("must have one field, found %d", num)
+		}
+		for key, field := range value.Fields {
+			if fieldDecl, ok := decl.ForKey(key); !ok {
+				return fmt.Errorf("field %s: unknown", key)
+			} else if err := fieldDecl.conforms(field); err != nil {
+				return fmt.Errorf("field %s: %s", key, err)
+			}
+		}
+		return nil
+	}
+}
+
 type schema fidlir.Root
 
 // LookupDeclByName looks up a message declaration by name.
@@ -294,6 +346,14 @@ func (s schema) LookupDeclByName(name string) (Declaration, bool) {
 			}, true
 		}
 	}
+	for _, decl := range s.Unions {
+		if decl.Name == s.name(name) {
+			return &UnionDecl{
+				Union:  decl,
+				schema: s,
+			}, true
+		}
+	}
 	// TODO(pascallouis): add support missing declarations (e.g. xunions)
 	return nil, false
 }
@@ -303,7 +363,7 @@ func (s schema) LookupDeclByType(typ fidlir.Type) (Declaration, bool) {
 	switch typ.Kind {
 	case fidlir.StringType:
 		return &stringDecl{
-			bound: *typ.ElementCount,
+			bound: typ.ElementCount,
 		}, true
 	case fidlir.PrimitiveType:
 		switch typ.PrimitiveSubtype {