Merge pull request #6 from AaronWebster/295268857

Fix bug in parameterized view copy constructor.
diff --git a/compiler/back_end/cpp/generated_code_templates b/compiler/back_end/cpp/generated_code_templates
index 09d8756..dcc82b6 100644
--- a/compiler/back_end/cpp/generated_code_templates
+++ b/compiler/back_end/cpp/generated_code_templates
@@ -80,7 +80,8 @@
   template <typename OtherStorage>
   Generic$_name_$View(
       const Generic$_name_$View<OtherStorage> &emboss_reserved_local_other)
-      : backing_{emboss_reserved_local_other.BackingStorage()} {}
+      : backing_{emboss_reserved_local_other.BackingStorage()}
+        $_parameter_copy_initializers_$ {}
 
   // Allow pass-through construction of backing_, but only if there is at least
   // one argument, and, if exactly one argument, that argument is not a
diff --git a/compiler/back_end/cpp/header_generator.py b/compiler/back_end/cpp/header_generator.py
index d3289c2..109686c 100644
--- a/compiler/back_end/cpp/header_generator.py
+++ b/compiler/back_end/cpp/header_generator.py
@@ -225,6 +225,7 @@
 def _get_adapted_cpp_buffer_type_for_field(type_definition, size_in_bits,
                                            buffer_type, byte_order,
                                            parent_addressable_unit):
+  """Returns the adapted C++ type information needed to construct a view."""
   if (parent_addressable_unit == ir_pb2.TypeDefinition.BYTE and
       type_definition.addressable_unit == ir_pb2.TypeDefinition.BIT):
     assert byte_order
@@ -1012,6 +1013,7 @@
   constructor_parameters = []
   forwarded_parameters = []
   parameter_initializers = []
+  parameter_copy_initializers = []
   units = {1: "Bits", 8: "Bytes"}[type_ir.addressable_unit]
 
   for subtype in type_ir.subtype:
@@ -1030,9 +1032,12 @@
     parameter_fields.append("{} {}_;".format(parameter_type, parameter_name))
     constructor_parameters.append(
         "{} {}, ".format(parameter_type, parameter_name))
-    forwarded_parameters.append(
-        "::std::forward</**/{}>({}),".format(parameter_type, parameter_name))
+    forwarded_parameters.append("::std::forward</**/{}>({}),".format(
+        parameter_type, parameter_name))
     parameter_initializers.append(", {0}_({0})".format(parameter_name))
+    parameter_copy_initializers.append(
+        ", {0}_(emboss_reserved_local_other.{0}_)".format(parameter_name))
+
     field_method_declarations.append(
         code_template.format_template(
             _TEMPLATES.structure_single_parameter_field_method_declarations,
@@ -1047,6 +1052,8 @@
                                       field=parameter_name + "()"))
   if type_ir.runtime_parameter:
     flag_name = "parameters_initialized_"
+    parameter_copy_initializers.append(
+        ", {0}(emboss_reserved_local_other.{0})".format(flag_name))
     parameters_initialized_flag = "bool {} = false;".format(flag_name)
     initialize_parameters_initialized_true = ", {}(true)".format(flag_name)
     parameter_checks = ["if (!{}) return false;".format(flag_name)]
@@ -1123,6 +1130,7 @@
       constructor_parameters="".join(constructor_parameters),
       forwarded_parameters="".join(forwarded_parameters),
       parameter_initializers="\n".join(parameter_initializers),
+      parameter_copy_initializers="\n".join(parameter_copy_initializers),
       parameters_initialized_flag=parameters_initialized_flag,
       initialize_parameters_initialized_true=(
           initialize_parameters_initialized_true),
diff --git a/compiler/back_end/cpp/testcode/parameters_test.cc b/compiler/back_end/cpp/testcode/parameters_test.cc
index 68b5f09..fd7d53c 100644
--- a/compiler/back_end/cpp/testcode/parameters_test.cc
+++ b/compiler/back_end/cpp/testcode/parameters_test.cc
@@ -22,9 +22,33 @@
 #include "gtest/gtest.h"
 #include "testdata/parameters.emb.h"
 
-namespace emboss_test {
+namespace emboss {
+namespace test {
 namespace {
 
+TEST(AxisPair, Construction) {
+  ::std::array<char, 12> values = {1, 0, 0, 0, 2, 0, 0, 0};
+  auto view = MakeAxisPairView(AxisType::X_AXIS, AxisType::Y_AXIS, &values);
+
+  EXPECT_TRUE(view.Ok());
+
+  EXPECT_EQ(view.axis_type_a().Read(), AxisType::X_AXIS);
+  EXPECT_EQ(1U, view.axis_a().value().Read());
+
+  EXPECT_EQ(view.axis_type_b().Read(), AxisType::Y_AXIS);
+  EXPECT_EQ(2U, view.axis_b().value().Read());
+}
+
+TEST(AxisPair, Copy) {
+  ::std::array<char, 12> values = {1, 0, 0, 0, 2, 0, 0, 0};
+  auto view1 = MakeAxisPairView(AxisType::X_AXIS, AxisType::Y_AXIS, &values);
+  auto view2 = view1;
+
+  EXPECT_EQ(view1.Ok(), view2.Ok());
+  EXPECT_EQ(view1.axis_a().axis_type().Read(),
+            view2.axis_a().axis_type().Read());
+}
+
 TEST(Axes, Construction) {
   ::std::array<char, 12> values = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0};
   auto view = MakeAxesView(2, &values);
@@ -48,6 +72,20 @@
   EXPECT_FALSE(view.Ok());
 }
 
+TEST(Axes, Copy) {
+  ::std::array<char, 12> values = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0};
+  auto view1 = MakeAxesView(2, &values);
+  auto view2 = view1;
+
+  EXPECT_EQ(view1.Ok(), view2.Ok());
+  EXPECT_EQ(view1.values().ElementCount(), view2.values().ElementCount());
+  EXPECT_EQ(view1.values()[0].value().Read(), view2.values()[0].value().Read());
+  EXPECT_EQ(view1.x().x().Read(), view2.x().x().Read());
+  EXPECT_EQ(view1.values()[1].value().Read(), view2.values()[1].value().Read());
+  EXPECT_EQ(view1.y().y().Read(), view2.y().y().Read());
+  EXPECT_EQ(view1.has_z().Value(), view2.has_z().Value());
+}
+
 TEST(Axes, VirtualUsingParameter) {
   ::std::array<char, 12> values = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0};
   auto view = MakeAxesView(2, &values);
@@ -70,26 +108,26 @@
   EXPECT_FALSE(view.axes().Ok());
 }
 
-TEST(Multiversion, ParameterPassedDown) {
+TEST(MultiVersion, ParameterPassedDown) {
   ::std::array<char, 13> values = {0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0};
-  auto view = MakeMultiversionView(Product::VERSION_1, &values);
+  auto view = MakeMultiVersionView(Product::VERSION_1, &values);
   EXPECT_TRUE(view.Ok());
   EXPECT_EQ(2U, view.axes().y().y().Read());
   EXPECT_FALSE(view.axes().has_z().Value());
-  view = MakeMultiversionView(Product::VERSION_X, &values);
+  view = MakeMultiVersionView(Product::VERSION_X, &values);
   EXPECT_TRUE(view.Ok());
   EXPECT_EQ(2U, view.axes().y().y().Read());
   EXPECT_TRUE(view.axes().has_z().Value());
 }
 
-TEST(Multiversion, ParameterUsedToSwitchField) {
+TEST(MultiVersion, ParameterUsedToSwitchField) {
   ::std::array<unsigned char, 9> values = {1, 0, 0, 0, 0x80, 0, 100, 0, 0};
-  auto view = MakeMultiversionView(Product::VERSION_1, &values);
+  auto view = MakeMultiVersionView(Product::VERSION_1, &values);
   EXPECT_TRUE(view.Ok());
   EXPECT_TRUE(view.config().power().Read());
   EXPECT_FALSE(view.has_config_vx().Value());
   EXPECT_EQ(5U, view.SizeInBytes());
-  view = MakeMultiversionView(Product::VERSION_X, &values);
+  view = MakeMultiVersionView(Product::VERSION_X, &values);
   EXPECT_TRUE(view.Ok());
   EXPECT_TRUE(view.config().power().Read());
   EXPECT_TRUE(view.has_config_vx().Value());
@@ -136,4 +174,5 @@
 }
 
 }  // namespace
-}  // namespace emboss_test
+}  // namespace test
+}  // namespace emboss
diff --git a/testdata/parameters.emb b/testdata/parameters.emb
index 9c28f24..2f629f3 100644
--- a/testdata/parameters.emb
+++ b/testdata/parameters.emb
@@ -20,56 +20,80 @@
   VERSION_2 = 10
   VERSION_X = 23
 
+
 enum MessageId:
-  AXIS = 0
+  AXIS   = 0
   CONFIG = 1
 
-struct Multiversion(product: Product):
-  0 [+1]     MessageId                            message_id
+
+struct MultiVersion(product: Product):
+  0 [+1]     MessageId                                   message_id
   if message_id == MessageId.AXIS:
     1 [+12]  Axes(product == Product.VERSION_X ? 3 : 2)  axes
+
   if message_id == MessageId.CONFIG:
-    1 [+4]  Config                                config
+    1 [+4]   Config                                      config
+
   if product == Product.VERSION_X && message_id == MessageId.CONFIG:
-    1 [+8]  ConfigVX()                            config_vx
+    1 [+8]   ConfigVX()                                  config_vx
+
 
 struct Axes(axes: UInt:4):
-  0 [+axes * 4]  Axis(AxisType.GENERIC)[]  values
+  0 [+axes*4]  Axis(AxisType.GENERIC)[]  values
   if axes > 0:
-    0 [+4]       Axis(AxisType.X_AXIS)     x
+    0 [+4]     Axis(AxisType.X_AXIS)     x
+
   if axes > 1:
-    4 [+4]       Axis(AxisType.Y_AXIS)     y
+    4 [+4]     Axis(AxisType.Y_AXIS)     y
+
   if axes > 2:
-    8 [+4]       Axis(AxisType.Z_AXIS)     z
-  let axis_count_plus_one = axes + 1
+    8 [+4]     Axis(AxisType.Z_AXIS)     z
+
+  let axis_count_plus_one = axes+1
+
+
+struct AxisPair(axis_type_a_parameter: AxisType, axis_type_b_parameter: AxisType):
+  0 [+4]  Axis(axis_type_a)  axis_a
+  4 [+4]  Axis(axis_type_b)  axis_b
+  let axis_type_a = axis_type_a_parameter
+  let axis_type_b = axis_type_b_parameter
+
 
 struct AxesEnvelope:
   0 [+1]             UInt:8            axis_count
   1 [+axis_count*4]  Axes(axis_count)  axes
 
+
 enum AxisType:
   GENERIC = -1
-  X_AXIS = 1
-  Y_AXIS = 2
-  Z_AXIS = 3
+  X_AXIS  = 1
+  Y_AXIS  = 2
+  Z_AXIS  = 3
+
 
 struct Axis(axis_type_parameter: AxisType):
-  let axis_type = axis_type_parameter
-  0 [+4]  UInt:32  value
+  0 [+4]    UInt:32  value
   if axis_type == AxisType.X_AXIS:
     0 [+4]  UInt:32  x
+
   if axis_type == AxisType.Y_AXIS:
     0 [+4]  UInt:32  y
+
   if axis_type == AxisType.Z_AXIS:
     0 [+4]  UInt:32  z
 
+  let axis_type = axis_type_parameter
+
+
 bits Config():
   31 [+1]  Flag  power
 
+
 struct ConfigVX:
-  0 [+4]  bits:
-    31 [+1]  Flag  power
-  4 [+4]     UInt  gain
+  0  [+4]  bits:
+    31 [+1]       Flag  power
+
+  4  [+4]         UInt  gain
 
 
 struct StructWithUnusedParameter(x: UInt:8):
@@ -78,13 +102,15 @@
 # StructContainingStructWithUnusedParameter is used to ensure that a struct is
 # not Ok() if it does not have its parameters, even if it does not directly use
 # those parameters.
+
+
 struct StructContainingStructWithUnusedParameter:
   0 [+1]  StructWithUnusedParameter(x)  swup
   1 [+1]  UInt                          x
 
 struct BiasedValue(bias: UInt:8):
   0 [+1]  UInt  raw_value
-  let value = raw_value + bias
+  let value = raw_value+bias
 
 struct VirtualFirstFieldWithParam(param: UInt:8):
   # Regression test: virtual fields did not have `public:` annotations, causing