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(