You can specify the type of the loop parameter where the discrete range is a range of values of a specified scalar type:
entity enum is
end entity;
architecture enum_range of enum is
type tp is (red,green,blue,yellow);
signal sg: tp := red;
begin
process (sg)
begin
for i in tp range red to yellow loop
if sg = i then
report "sg = " & tp'image(sg);
end if;
end loop;
end process;
end architecture;
This produces:
enum.vhdl:12:17:@0ms:(report note): sg = red
TL;DR explanation
IEEE Std 1076-2008 10.10 Loop statement
iteration_scheme ::=
while condition
| for loop_parameter_specification
parameter_specification ::=
identifier in discrete_range
and
For a loop statement with a for iteration scheme, the loop parameter specification is the declaration of the loop parameter with the given identifier. The loop parameter is an object whose type is the base type of the discrete range. Within the sequence of statements, the loop parameter is a constant. Hence, a loop parameter is not allowed as the target of an assignment statement. Similarly, the loop parameter shall not be given as an actual corresponding to a formal of mode out or inout in an association list.
For the execution of a loop with a for iteration scheme, the discrete range is first evaluated. If the discrete range is a null range, the iteration scheme is said to be complete and the execution of the loop statement is therefore complete; otherwise, the sequence of statements is executed once for each value of the discrete range (subject to the loop not being left as a consequence of the execution of a next statement, an exit statement, or a return statement), after which the iteration scheme is said to be complete. Prior to each such iteration, the corresponding value of the discrete range is assigned to the loop parameter. These values are assigned in left-to-right order.
5.3.2 Array types, 5.3.2.1 General
discrete_range ::= discrete_subtype_indication | range
5.3.2.2 Subtype indications
subtype_indication ::=
[ resolution_indication ] type_mark [ constraint ]
constraint ::=
range_constraint
| array_constraint
| record_constraint
5.2 Scalar types 5.2.1 General
range_constraint ::= range range
range ::= range_attribute_name
| simple_expression direction simple_expression
direction ::= to | downto
It helps to understand how defining a range as the discrete range works. Without specifying a subtype indication in the discrete range the type is derived from the simple expressions in the range. The type of a numeric literal (9.3.2 Literals) is universal_integer convertible to type integer. The type can also be supplied by attribute as Matthew Taylor shows. Only dipping a toe in simple_expression (9.1) term -> factor -> primary, a primary can be a name (attribute name, 8.6) or a literal.
BNF other than found in Annex C (informative) Syntax summary, is normative.