Add support for `maximum_bits` and `is_signed` on `enum`s.
diff --git a/compiler/front_end/attribute_checker.py b/compiler/front_end/attribute_checker.py
index 92dd939..27e6722 100644
--- a/compiler/front_end/attribute_checker.py
+++ b/compiler/front_end/attribute_checker.py
@@ -35,6 +35,10 @@
 _MUST_BE_CONSTANT_MESSAGE = "Attribute '{name}' must have a constant value."
 
 
+# Default value for maximum_bits on an `enum`.
+_DEFAULT_ENUM_MAXIMUM_BITS = 64
+
+
 # Attribute type checkers
 def _is_constant_boolean(attr, module_source_file):
   """Checks if the given attr is a constant boolean."""
@@ -108,8 +112,10 @@
 _ATTRIBUTE_TYPES = {
     ("", attributes.ADDRESSABLE_UNIT_SIZE): _is_constant_integer,
     ("", attributes.BYTE_ORDER): _is_valid_byte_order,
+    ("", attributes.ENUM_MAXIMUM_BITS): _is_constant_integer,
     ("", attributes.FIXED_SIZE): _is_constant_integer,
     ("", attributes.IS_INTEGER): _is_constant_boolean,
+    ("", attributes.IS_SIGNED): _is_constant_boolean,
     ("", attributes.REQUIRES): _is_boolean,
     ("", attributes.STATIC_REQUIREMENTS): _is_boolean,
     ("", attributes.TEXT_OUTPUT): _is_valid_text_output,
@@ -125,16 +131,15 @@
 _BITS_ATTRIBUTES = {
     ("", attributes.FIXED_SIZE, False),
     ("", attributes.REQUIRES, False),
-    ("", attributes.STATIC_REQUIREMENTS, False),
 }
 _STRUCT_ATTRIBUTES = {
     ("", attributes.FIXED_SIZE, False),
     ("", attributes.BYTE_ORDER, True),
     ("", attributes.REQUIRES, False),
-    ("", attributes.STATIC_REQUIREMENTS, False),
 }
 _ENUM_ATTRIBUTES = {
-    ("", attributes.STATIC_REQUIREMENTS, False),
+    ("", attributes.ENUM_MAXIMUM_BITS, False),
+    ("", attributes.IS_SIGNED, False),
 }
 _EXTERNAL_ATTRIBUTES = {
     ("", attributes.ADDRESSABLE_UNIT_SIZE, False),
@@ -166,7 +171,23 @@
                                          maximum_value=str(value))),
           source_location=source_location),
       source_location=source_location)
-  return ir_pb2.Attribute(name=ir_pb2.Word(text=name),
+  return ir_pb2.Attribute(name=ir_pb2.Word(text=name,
+                                           source_location=source_location),
+                          value=attr_value,
+                          source_location=source_location)
+
+
+def _construct_boolean_attribute(name, value, source_location):
+  """Constructs a boolean Attribute with the given name and value."""
+  attr_value = ir_pb2.AttributeValue(
+      expression=ir_pb2.Expression(
+          boolean_constant=ir_pb2.BooleanConstant(
+              value=value, source_location=source_location),
+          type=ir_pb2.ExpressionType(boolean=ir_pb2.BooleanType(value=value)),
+          source_location=source_location),
+      source_location=source_location)
+  return ir_pb2.Attribute(name=ir_pb2.Word(text=name,
+                                           source_location=source_location),
                           value=attr_value,
                           source_location=source_location)
 
@@ -425,6 +446,30 @@
   # _verify_addressable_unit_attribute_on_external, below.
 
 
+def _add_missing_width_and_sign_attributes_on_enum(enum, type_definition):
+  """Sets the maximum_bits and is_signed attributes for an enum, if needed."""
+  max_bits_attr = ir_util.get_integer_attribute(type_definition.attribute,
+                                                attributes.ENUM_MAXIMUM_BITS)
+  if max_bits_attr is None:
+    type_definition.attribute.extend([
+        _construct_integer_attribute(attributes.ENUM_MAXIMUM_BITS,
+                                     _DEFAULT_ENUM_MAXIMUM_BITS,
+                                     type_definition.source_location)])
+  signed_attr = ir_util.get_boolean_attribute(type_definition.attribute,
+                                              attributes.IS_SIGNED)
+  if signed_attr is None:
+    for value in enum.value:
+      numeric_value = ir_util.constant_value(value.value)
+      if numeric_value < 0:
+        is_signed = True
+        break
+    else:
+      is_signed = False
+    type_definition.attribute.extend([
+        _construct_boolean_attribute(attributes.IS_SIGNED, is_signed,
+                                     type_definition.source_location)])
+
+
 def _verify_byte_order_attribute_on_field(field, type_definition,
                                           source_file_name, ir, errors):
   """Verifies the byte_order attribute on the given field."""
@@ -496,6 +541,22 @@
     ])
 
 
+def _verify_width_attribute_on_enum(enum, type_definition, source_file_name,
+                                    errors):
+  """Verifies the maximum_bits attribute for an enum TypeDefinition."""
+  max_bits_value = ir_util.get_integer_attribute(type_definition.attribute,
+                                                attributes.ENUM_MAXIMUM_BITS)
+  # The attribute should already have been defaulted, if not originally present.
+  assert max_bits_value is not None, "maximum_bits not set"
+  if max_bits_value > 64 or max_bits_value < 1:
+    max_bits_attr = ir_util.get_attribute(type_definition.attribute,
+                                          attributes.ENUM_MAXIMUM_BITS)
+    errors.append([
+        error.error(source_file_name, max_bits_attr.source_location,
+                    "'maximum_bits' on an 'enum' must be between 1 and 64.")
+    ])
+
+
 def _gather_default_attributes(obj, defaults):
   defaults = defaults.copy()
   for attr in obj.attribute:
@@ -512,6 +573,8 @@
   traverse_ir.fast_traverse_ir_top_down(
       ir, [ir_pb2.External], _add_addressable_unit_to_external)
   traverse_ir.fast_traverse_ir_top_down(
+      ir, [ir_pb2.Enum], _add_missing_width_and_sign_attributes_on_enum)
+  traverse_ir.fast_traverse_ir_top_down(
       ir, [ir_pb2.Structure], _add_missing_size_attributes_on_structure,
       incidental_actions={
           ir_pb2.Module: _gather_default_attributes,
@@ -544,6 +607,9 @@
       ir, [ir_pb2.Structure], _verify_size_attributes_on_structure,
       parameters={"errors": errors})
   traverse_ir.fast_traverse_ir_top_down(
+      ir, [ir_pb2.Enum], _verify_width_attribute_on_enum,
+      parameters={"errors": errors})
+  traverse_ir.fast_traverse_ir_top_down(
       ir, [ir_pb2.External], _verify_addressable_unit_attribute_on_external,
       parameters={"errors": errors})
   traverse_ir.fast_traverse_ir_top_down(
diff --git a/compiler/front_end/attribute_checker_test.py b/compiler/front_end/attribute_checker_test.py
index d57d602..efae0e6 100644
--- a/compiler/front_end/attribute_checker_test.py
+++ b/compiler/front_end/attribute_checker_test.py
@@ -26,6 +26,8 @@
 # of the contract with back ends.
 _BYTE_ORDER = "byte_order"
 _FIXED_SIZE = "fixed_size_in_bits"
+_IS_SIGNED = "is_signed"
+_MAX_BITS = "maximum_bits"
 
 
 def _make_ir_from_emb(emb_text, name="m.emb"):
@@ -584,6 +586,75 @@
                       "enumeration, or boolean fields.")]],
         error.filter_errors(attribute_checker.normalize_and_verify(ir)))
 
+  def test_adds_false_is_signed_attribute(self):
+    ir = _make_ir_from_emb("enum Foo:\n"
+                           "  ZERO = 0\n")
+    self.assertEqual([], attribute_checker.normalize_and_verify(ir))
+    enum = ir.module[0].type[0]
+    is_signed_attr = ir_util.get_attribute(enum.attribute, _IS_SIGNED)
+    self.assertTrue(is_signed_attr.expression.HasField("boolean_constant"))
+    self.assertFalse(is_signed_attr.expression.boolean_constant.value)
+
+  def test_leaves_is_signed_attribute(self):
+    ir = _make_ir_from_emb("enum Foo:\n"
+                           "  [is_signed: true]\n"
+                           "  ZERO = 0\n")
+    self.assertEqual([], attribute_checker.normalize_and_verify(ir))
+    enum = ir.module[0].type[0]
+    is_signed_attr = ir_util.get_attribute(enum.attribute, _IS_SIGNED)
+    self.assertTrue(is_signed_attr.expression.HasField("boolean_constant"))
+    self.assertTrue(is_signed_attr.expression.boolean_constant.value)
+
+  def test_adds_true_is_signed_attribute(self):
+    ir = _make_ir_from_emb("enum Foo:\n"
+                           "  NEGATIVE_ONE = -1\n")
+    self.assertEqual([], attribute_checker.normalize_and_verify(ir))
+    enum = ir.module[0].type[0]
+    is_signed_attr = ir_util.get_attribute(enum.attribute, _IS_SIGNED)
+    self.assertTrue(is_signed_attr.expression.HasField("boolean_constant"))
+    self.assertTrue(is_signed_attr.expression.boolean_constant.value)
+
+  def test_adds_max_bits_attribute(self):
+    ir = _make_ir_from_emb("enum Foo:\n"
+                           "  ZERO = 0\n")
+    self.assertEqual([], attribute_checker.normalize_and_verify(ir))
+    enum = ir.module[0].type[0]
+    max_bits_attr = ir_util.get_attribute(enum.attribute, _MAX_BITS)
+    self.assertTrue(max_bits_attr.expression.HasField("constant"))
+    self.assertEqual("64", max_bits_attr.expression.constant.value)
+
+  def test_leaves_max_bits_attribute(self):
+    ir = _make_ir_from_emb("enum Foo:\n"
+                           "  [maximum_bits: 32]\n"
+                           "  ZERO = 0\n")
+    self.assertEqual([], attribute_checker.normalize_and_verify(ir))
+    enum = ir.module[0].type[0]
+    max_bits_attr = ir_util.get_attribute(enum.attribute, _MAX_BITS)
+    self.assertTrue(max_bits_attr.expression.HasField("constant"))
+    self.assertEqual("32", max_bits_attr.expression.constant.value)
+
+  def test_rejects_too_small_max_bits(self):
+    ir = _make_ir_from_emb("enum Foo:\n"
+                           "  [maximum_bits: 0]\n"
+                           "  ZERO = 0\n")
+    attribute_ir = ir.module[0].type[0].attribute[0]
+    self.assertEqual(
+        [[error.error(
+            "m.emb", attribute_ir.value.source_location,
+            "'maximum_bits' on an 'enum' must be between 1 and 64.")]],
+        error.filter_errors(attribute_checker.normalize_and_verify(ir)))
+
+  def test_rejects_too_large_max_bits(self):
+    ir = _make_ir_from_emb("enum Foo:\n"
+                           "  [maximum_bits: 65]\n"
+                           "  ZERO = 0\n")
+    attribute_ir = ir.module[0].type[0].attribute[0]
+    self.assertEqual(
+        [[error.error(
+            "m.emb", attribute_ir.value.source_location,
+            "'maximum_bits' on an 'enum' must be between 1 and 64.")]],
+        error.filter_errors(attribute_checker.normalize_and_verify(ir)))
+
 
 if __name__ == "__main__":
   unittest.main()
diff --git a/compiler/front_end/attributes.py b/compiler/front_end/attributes.py
index fd6e31c..f931f5b 100644
--- a/compiler/front_end/attributes.py
+++ b/compiler/front_end/attributes.py
@@ -23,3 +23,5 @@
 REQUIRES = "requires"
 STATIC_REQUIREMENTS = "static_requirements"
 TEXT_OUTPUT = "text_output"
+ENUM_MAXIMUM_BITS = "maximum_bits"
+IS_SIGNED = "is_signed"
diff --git a/compiler/front_end/constraints.py b/compiler/front_end/constraints.py
index 9af1b17..6beaf31 100644
--- a/compiler/front_end/constraints.py
+++ b/compiler/front_end/constraints.py
@@ -134,30 +134,29 @@
     ])
 
 
-def _check_that_enum_values_are_representable(enum_type, source_file_name,
-                                              errors):
-  """Checks that enumeration values can fit in an int64 or uint64."""
+def _check_that_enum_values_are_representable(enum_type, type_definition,
+                                              source_file_name, errors):
+  """Checks that enumeration values can fit in their specified int type."""
   values = []
+  max_enum_size = ir_util.get_integer_attribute(
+      type_definition.attribute, attributes.ENUM_MAXIMUM_BITS)
+  is_signed = ir_util.get_boolean_attribute(
+      type_definition.attribute, attributes.IS_SIGNED)
+  if is_signed:
+    enum_range = (-(2**(max_enum_size-1)), 2**(max_enum_size-1)-1)
+  else:
+    enum_range = (0, 2**max_enum_size-1)
   for value in enum_type.value:
     values.append((ir_util.constant_value(value.value), value))
-  # Guess if the user intended a signed or unsigned enumeration based on how
-  # many values would be out of range given either type.
-  signed_out_of_range = [v for v in values if not -2**63 <= v[0] <= 2**63-1]
-  unsigned_out_of_range = [v for v in values if not 0 <= v[0] <= 2**64-1]
-  if len(signed_out_of_range) < len(unsigned_out_of_range):
-    out_of_range = signed_out_of_range
-    range_name = "signed "
-  else:
-    out_of_range = unsigned_out_of_range
-    range_name = "unsigned "
-  # If all values are in range for either a signed or an unsigned enumeration,
-  # this loop will have zero iterations.
+  out_of_range = [v for v in values
+                  if not enum_range[0] <= v[0] <= enum_range[1]]
+  # If all values are in range, this loop will have zero iterations.
   for value in out_of_range:
     errors.append([
         error.error(
             source_file_name, value[1].value.source_location,
-            "Value {} is out of range for {}enumeration.".format(
-                value[0], range_name if -2**63 <= value[0] <= 2**64-1 else ""))
+            "Value {} is out of range for {}-bit {} enumeration.".format(
+                value[0], max_enum_size, "signed" if is_signed else "unsigned"))
     ])
 
 
@@ -297,10 +296,6 @@
   """Checks that the given atomic `type_ir` is allowed to be `size` bits."""
   referenced_type_definition = ir_util.find_object(
       type_ir.atomic_type.reference, ir)
-  # TODO(bolms): replace this with a check against an automatically-generated
-  # `static_requirements` attribute on enum types.  (The main problem is that
-  # the generated attribute would have no source text, so there would be a crash
-  # when trying to display the error.)
   if referenced_type_definition.HasField("enumeration"):
     if size is None:
       return [[
@@ -309,14 +304,18 @@
               "Enumeration {} cannot be placed in a dynamically-sized "
               "field.".format(_render_type(type_ir, ir)))
       ]]
-    elif size < 1 or size > 64:
-      return [[
-          error.error(
-              source_file_name, type_ir.source_location,
-              "Enumeration {} cannot be {} bits; enumerations must be between "
-              "1 and 64 bits, inclusive.".format(
-                  _render_atomic_type_name(type_ir, ir), size))
-      ]]
+    else:
+      max_enum_size = ir_util.get_integer_attribute(
+          referenced_type_definition.attribute, attributes.ENUM_MAXIMUM_BITS)
+      if size < 1 or size > max_enum_size:
+        return [[
+            error.error(
+                source_file_name, type_ir.source_location,
+                "Enumeration {} cannot be {} bits; {} must be between "
+                "1 and {} bits, inclusive.".format(
+                    _render_atomic_type_name(type_ir, ir), size,
+                    _render_atomic_type_name(type_ir, ir), max_enum_size))
+        ]]
 
   if size is None:
     bindings = {"$is_statically_sized": False}
diff --git a/compiler/front_end/constraints_test.py b/compiler/front_end/constraints_test.py
index ff33586..9bf5a8e 100644
--- a/compiler/front_end/constraints_test.py
+++ b/compiler/front_end/constraints_test.py
@@ -282,7 +282,7 @@
     error_type = ir.module[0].type[0].structure.field[0].type
     self.assertEqual([[
         error.error("m.emb", error_type.source_location,
-                    "Enumeration type 'Bar' cannot be 0 bits; enumerations "
+                    "Enumeration type 'Bar' cannot be 0 bits; type 'Bar' "
                     "must be between 1 and 64 bits, inclusive."),
     ]], error.filter_errors(constraints.check_constraints(ir)))
 
@@ -331,10 +331,24 @@
     error_type = ir.module[0].type[0].structure.field[0].type
     self.assertEqual([[
         error.error("m.emb", error_type.source_location,
-                    "Enumeration type 'Bar' cannot be 72 bits; enumerations "
+                    "Enumeration type 'Bar' cannot be 72 bits; type 'Bar' " +
                     "must be between 1 and 64 bits, inclusive."),
     ]], error.filter_errors(constraints.check_constraints(ir)))
 
+  def test_explicit_enumeration_size_too_big_for_small_enum(self):
+    ir = _make_ir_from_emb('[$default byte_order: "BigEndian"]\n'
+                           "struct Foo:\n"
+                           "  0 [+8]  Bar  sixty_four_bit\n"
+                           "enum Bar:\n"
+                           "  [maximum_bits: 63]\n"
+                           "  BAZ = 0\n")
+    error_type = ir.module[0].type[0].structure.field[0].type
+    self.assertEqual([[
+        error.error("m.emb", error_type.source_location,
+                    "Enumeration type 'Bar' cannot be 64 bits; type 'Bar' " +
+                    "must be between 1 and 63 bits, inclusive."),
+    ]], error.filter_errors(constraints.check_constraints(ir)))
+
   def test_explicit_size_on_fixed_size_type(self):
     ir = _make_ir_from_emb("struct Foo:\n"
                            "  0 [+1]  Byte:8  one_byte\n"
@@ -417,7 +431,8 @@
             # TODO(bolms): Try to print numbers like 2**64 in hex?  (I.e., if a
             # number is a round number in hex, but not in decimal, print in
             # hex?)
-            "Value 18446744073709551616 is out of range for enumeration.")]
+            "Value 18446744073709551616 is out of range for 64-bit unsigned " +
+            "enumeration.")]
     ], constraints.check_constraints(ir))
 
   def test_enum_value_too_low(self):
@@ -428,7 +443,8 @@
     self.assertEqual([
         [error.error(
             "m.emb", error_value.source_location,
-            "Value -9223372036854775809 is out of range for enumeration.")]
+            "Value -9223372036854775809 is out of range for 64-bit signed " +
+            "enumeration.")]
     ], constraints.check_constraints(ir))
 
   def test_enum_value_too_wide(self):
@@ -436,11 +452,12 @@
                            "enum Foo:\n"
                            "  LOW = -1\n"
                            "  HIGH = 0x8000_0000_0000_0000\n")
-    error_value = ir.module[0].type[0].enumeration.value[0].value
+    error_value = ir.module[0].type[0].enumeration.value[1].value
     self.assertEqual([[
         error.error(
             "m.emb", error_value.source_location,
-            "Value -1 is out of range for unsigned enumeration.")
+            "Value 9223372036854775808 is out of range for 64-bit signed " +
+            "enumeration.")
     ]], error.filter_errors(constraints.check_constraints(ir)))
 
   def test_enum_value_too_wide_unsigned_error_message(self):
@@ -453,7 +470,33 @@
     self.assertEqual([[
         error.error(
             "m.emb", error_value.source_location,
-            "Value 9223372036854775808 is out of range for signed enumeration.")
+            "Value 9223372036854775808 is out of range for 64-bit signed " +
+            "enumeration.")
+    ]], error.filter_errors(constraints.check_constraints(ir)))
+
+  def test_enum_value_too_wide_small_size_error_message(self):
+    ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n'
+                           "enum Foo:\n"
+                           "  [maximum_bits: 8]\n"
+                           "  HIGH = 0x100\n")
+    error_value = ir.module[0].type[0].enumeration.value[0].value
+    self.assertEqual([[
+        error.error(
+            "m.emb", error_value.source_location,
+            "Value 256 is out of range for 8-bit unsigned enumeration.")
+    ]], error.filter_errors(constraints.check_constraints(ir)))
+
+  def test_enum_value_too_wide_small_size_signed_error_message(self):
+    ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n'
+                           "enum Foo:\n"
+                           "  [maximum_bits: 8]\n"
+                           "  [is_signed: true]\n"
+                           "  HIGH = 0x80\n")
+    error_value = ir.module[0].type[0].enumeration.value[0].value
+    self.assertEqual([[
+        error.error(
+            "m.emb", error_value.source_location,
+            "Value 128 is out of range for 8-bit signed enumeration.")
     ]], error.filter_errors(constraints.check_constraints(ir)))
 
   def test_enum_value_too_wide_multiple(self):
@@ -463,15 +506,17 @@
                            "  LOW2 = -1\n"
                            "  HIGH = 0x8000_0000_0000_0000\n"
                            "  HIGH2 = 0x8000_0000_0000_0001\n")
-    error_value = ir.module[0].type[0].enumeration.value[0].value
-    error_value2 = ir.module[0].type[0].enumeration.value[1].value
+    error_value = ir.module[0].type[0].enumeration.value[2].value
+    error_value2 = ir.module[0].type[0].enumeration.value[3].value
     self.assertEqual([
         [error.error(
             "m.emb", error_value.source_location,
-            "Value -2 is out of range for unsigned enumeration.")],
+            "Value 9223372036854775808 is out of range for 64-bit signed " +
+            "enumeration.")],
         [error.error(
             "m.emb", error_value2.source_location,
-            "Value -1 is out of range for unsigned enumeration.")]
+            "Value 9223372036854775809 is out of range for 64-bit signed " +
+            "enumeration.")]
     ], error.filter_errors(constraints.check_constraints(ir)))
 
   def test_enum_value_too_wide_multiple_signed_error_message(self):
@@ -487,11 +532,11 @@
     self.assertEqual([
         [error.error(
             "m.emb", error_value.source_location,
-            "Value 9223372036854775808 is out of range for signed "
+            "Value 9223372036854775808 is out of range for 64-bit signed "
             "enumeration.")],
         [error.error(
             "m.emb", error_value2.source_location,
-            "Value 9223372036854775809 is out of range for signed "
+            "Value 9223372036854775809 is out of range for 64-bit signed "
             "enumeration.")]
     ], error.filter_errors(constraints.check_constraints(ir)))
 
@@ -501,15 +546,55 @@
                            "  LOW = -1\n"
                            "  HIGH = 0x8000_0000_0000_0000\n"
                            "  HIGH2 = 0x1_0000_0000_0000_0000\n")
-    error_value = ir.module[0].type[0].enumeration.value[0].value
+    error_value1 = ir.module[0].type[0].enumeration.value[1].value
     error_value2 = ir.module[0].type[0].enumeration.value[2].value
     self.assertEqual([
         [error.error(
-            "m.emb", error_value.source_location,
-            "Value -1 is out of range for unsigned enumeration.")],
+            "m.emb", error_value1.source_location,
+            "Value 9223372036854775808 is out of range for 64-bit signed " +
+            "enumeration.")],
         [error.error(
             "m.emb", error_value2.source_location,
-            "Value 18446744073709551616 is out of range for enumeration.")]
+            "Value 18446744073709551616 is out of range for 64-bit signed " +
+            "enumeration.")]
+    ], error.filter_errors(constraints.check_constraints(ir)))
+
+  def test_enum_value_explicitly_signed_error_message(self):
+    ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n'
+                           "enum Foo:\n"
+                           "  [is_signed: true]\n"
+                           "  HIGH = 0x8000_0000_0000_0000\n"
+                           "  HIGH2 = 0x1_0000_0000_0000_0000\n")
+    error_value0 = ir.module[0].type[0].enumeration.value[0].value
+    error_value1 = ir.module[0].type[0].enumeration.value[1].value
+    self.assertEqual([
+        [error.error(
+            "m.emb", error_value0.source_location,
+            "Value 9223372036854775808 is out of range for 64-bit signed " +
+            "enumeration.")],
+        [error.error(
+            "m.emb", error_value1.source_location,
+            "Value 18446744073709551616 is out of range for 64-bit signed " +
+            "enumeration.")]
+    ], error.filter_errors(constraints.check_constraints(ir)))
+
+  def test_enum_value_explicitly_unsigned_error_message(self):
+    ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n'
+                           "enum Foo:\n"
+                           "  [is_signed: false]\n"
+                           "  LOW = -1\n"
+                           "  HIGH = 0x8000_0000_0000_0000\n"
+                           "  HIGH2 = 0x1_0000_0000_0000_0000\n")
+    error_value0 = ir.module[0].type[0].enumeration.value[0].value
+    error_value2 = ir.module[0].type[0].enumeration.value[2].value
+    self.assertEqual([
+        [error.error(
+            "m.emb", error_value0.source_location,
+            "Value -1 is out of range for 64-bit unsigned enumeration.")],
+        [error.error(
+            "m.emb", error_value2.source_location,
+            "Value 18446744073709551616 is out of range for 64-bit unsigned " +
+            "enumeration.")]
     ], error.filter_errors(constraints.check_constraints(ir)))
 
   def test_explicit_non_byte_size_array_element(self):