--- ais/ai-00186.txt 2004/04/06 19:56:56 1.3 +++ ais/ai-00186.txt 2004/04/06 22:31:52 1.4 @@ -1,4 +1,4 @@ -!standard 03.05.04 (14) 04-03-23 AI95-00186/03 +!standard 03.05.04 (14) 04-04-01 AI95-00186/04 !standard 03.04 (9) !class binding interpretation 99-03-21 !status work item 97-03-19 @@ -9,11 +9,12 @@ !summary -An implementation may support integer or modular types which include -values outside the range System.Min_Int..System.Max_Int. In some cases -evaluation of a non-static root_integer expression outside this range is -required not to raise an exception. In most other such cases, the behavior -is defined to be implementation dependent. +The base range of root_integer is extended to include extra positive values +corresponding to modulartypes. The evaluation of expressions of type +root_integer is defined to be a bounded error in some cases where an +implementation cannot possibly find a type to perform the evaluation at run- +time. In other cases, such an evaluation is safe and portable, even in generics +with formal discrete types. !question @@ -34,109 +35,113 @@ !recommendation -If an implementation supports a modular type whose range exceeds -0..System.Max_Int, or a nonstandard integer type with values outside -System.Min_Int..System.Max_Int, non-static expressions which involve only -variables, constants, and attributes of the a type T or its subtypes, or -numeric_literals and other values of type root_integer may only raise -Constraint_Error if the process of evaluating the expression exceeds the -range of type T. - -If a non-static expression contains arithmetic operators of type root_real, -it is implementation defined whether or not Constraint_Error will be raised -if the result is outside the range of root_real, even if the result of the -expression is within the range of the target type. - -Let T be an integer or modular type which has values outside the range -System.Min_Int..System.Max_Int. If a non-static expression of type -root_integer has both an attribute, variable or result of type T and an -attribute, variable or result of some other type, it is erroneous for the -value of the expression to exceed the range of root_integer. +The base range of root_integer shall include at least System.Min_Int .. M where +M is the maximum of System.Max_Int and System.Max_Nonbinary_Modulus - 1. -An implementation is allowed to choose a range for root_real that exceeds -System.Min_Int..System.Max_Int. +Let T be a discrete type. It is a bounded error to evaluate an expression of +type root_integer if it contains simple_expressions of types T or T'Base +unless: + + o all simple_expressions of a discrete type are of types T, T'Base or + universal_integer; and + + o all subexpressions of type universal_integer or root_integer, as well as + the result of applying the T'Pos attribute to all subexpressions of types + T or T'Base, belong to the range: + + o System.Min_Int .. System.Max_Int if T is a signed integer type; or + o 0 .. System.Max_Nonbinary_Modulus - 1 if T is an enumeration or a + modular type. + +The possible outcomes are that the expression is evaluated correctly, +Constraint_Error is raised, or Program_Error is raised. + +<<Author's note: for enumeration types, the above rules work well in the absence +of an enumeration representation clause. However, if there is a clause that +gives negative representations for some literals, using a modular type for +internal computations won't work. Do we care? I want to make sure that +Wide_Wide_Character works, but enumeration representation clauses for huge +enumeration types are not too exciting.>> !wording -The second sentence of paragraph 3.4(9) should read: +See !recommendation. I'll write the words if we agree on the intent. -"For a scalar type {declared by a derived_type_definition}, the -base range of the derived type is the same as that of the parent type." - -Paragraph 3.5.4(14) should read: - -"A type defined by an integer_type_definition is implicitly derived -from _root_integer_, an anonymous predefined (specific) integer type, -whose base range is {at least} System.Min_Int..System.Max_Int. However, -the base range of the new type is not inherited from root_integer, but is -instead determined by the range or modulus specified by the -integer_type_definition. Integer literals are all of the type -_universal_integer_, the universal type (see 3.4.1) for the class rooted at -_root_integer_, allowing thier use with the operations of any integer type." - !discussion -The first wording change above is just to eliminate an apparent conflict in -the standard. The second sentence of 3.5.4(14) is correct, but since all -integer types are derived types, the paragraphs conflict. - -The main problem dealt with here is caused by the preference rule (see -8.6(29)) for root_integer. In theory this can cause expressions which -appear to involve only operations of of one numeric type to actually be -evaluated using the operations of root_integer. Consider for instance the -expression T'Val(T'Pos(X) - 3) where X is of type T. - -Although all the values in the expression are of either type T or -universal_integer, the subtraction operation is that of root_integer. -This seems irksome, but unlikely to occur even inside a generic with a -formal of a discrete type. However, there are more troubling cases. -Consider the Boolean expression S'Modulus > T'Modulus, where S and T are -modular subtypes. When is this illegal, guaranteed to work, or can -possibly raise Constraint_Error? If the answer depends on the staticness -of the subtypes, that way lies madness. (Note that in this particular -case, the expression can always be evaluated at compile time even if the -subtypes are static or generic formal subtypes.) - -Even more troubling is this case: - -type Modular is mod System.Max_Binary_Modulus; -.. -subtype Mod is Modular range...; -.. -Base_Modulus: constant := Mod'Modulus; - -Does this or should this raise Constraint_Error, or is it implementation -dependent? (It is implementation dependent if the subtype is non-static.) - -Now let's look at the other side for a minute. There are some truly ugly -cases such as X: Integer := Modular'Pos(Y) + Integer'Pos(Z); where Y and Z -are variables of the respective types. Here we have an expression that can -only be evaluated at run-time, and possibly no machine arithmetic types -that can be used safely, assuming that Integer and Modular are the largest -available integer and modular types respectively. - -The conclusion is that implementations should always be allowed to "do the -right thing" in the reasonable cases, and required not to raise -Constraint_Error in expressions without attributes of a single type but no -arithmetic operations. But rather than force implementations not to -provide otherwise useful types by requiring support of some pathological -cases, these case are made erroneous. It would be possible to make these -cases a bounded error, but such mixed expressions can (and should) always -be rewritten to make explicit which operations should be modular and where -overflow is wanted. By making such expressions erroneous only if they -exceed the range of root_integer, programmers can still use such -expressions if they know the possible ranges of all intermediate results. - -Finally this AI allows the range of root_integer to exceed -System.Min_Int..System.Max_Int. There is no point in allowing nonstandard -integer types if the implementations are then restricted from using them -where appropriate. For example, on a machine with a double-width -multiplication result and easy addition and subtraction for such values, it -would be useful to have that type as a nonstandard integer type, even if -some multiplication operators were not provided, and you couldn't use it -for indexing. It would be silly to prohibit using that type for evaluating -expressions of type root_real. Where possible this is the best solution to -the problem. +The main problem dealt with in this is that, because of the preference rule for +root_integer (8.6(29)) some expressions are evaluated at run-time using +root_integer. But in practice there is no good choice of range for root_integer +because it would ideally have to cover three ranges: + + System.Min_Int .. System.Max_Int -- For signed integer types. + 0 .. System.Max_Binary_Modulus - 1 -- For binary modular types. + 0 .. System.Max_Nonbinary_Modulus - 1 -- For nonbinary modular types. + +On a typical 32-bit machine, these ranges might be: + + -2 ** 31 .. 2 ** 31 - 1 + 0 .. 2 ** 32 - 1 + 0 .. 2 ** 32 - 2 + +It is clear that a 33-bit integer would be needed to cover their union. And +even such a type would not be able to represent T'Modulus for the largest +modular type. At any rate, we don't want to require implementations to have to +do multiple precision in the root_integer arithmetic. + +What we are doing here is essentially to specify circumstances under which an +implementation is _not_ allowed to raise Constraint_Error during evaluation of +an expression of type root_integer. This is phrased in terms of a bounded +error, because we want implementations to be able to detect anomalies by raising +an exception, or to do the correct evaluation, but we don't want to allow it to +go berserk. So this is not an erroneous situation. + +From the user's perspective, this AI guarantees that there is a class of +expressions which can always be evaluated safely (i.e., without raising an +exception) and portably, even in a generic with a formal discrete type. The +expression mentioned in the question is an example of this case. On the other +hand, evaluating the expression: + + T'Modulus > 3 + +is a bounded error if T is the largest modular type because T'Modulus cannot in +general be represented using root_integer. On the other hand, the expression: + + T'Last >= 3 + +is safe. + +The restriction on the expressions are intended to make it possible to evaluate +expressions of type root_integer using the largest signed integer type (if T is +signed) or the largest unsigned integer type (if T is modular or enumeration). +The rules ensure that an implementation doesn't have to handle expressions +involving mixed discrete types, as in: + + Signed_Int'Pos (Signed_Int'First) + Unsigned_Int'Pos (Unsigned_Int'Last) + +because such expressions could require multiple precision. An implementation +could just recognize this situation (at compile-time) and raise Program_Error. +Or it could use a signed integer and raise Constraint_Error on the conversion +of Unsigned_Int'Last. + +For macro-expanded generics, the nature of actual types is always known in an +instance, so it should be straightforward to generate signed or unsigned +arithmetic as needed. For shared generics the situation is a bit more +complicated (as usual) but a possible implementation technique is to generate +both signed and unsigned code, and select the appropriate code based on the +nature of the type. + +Finally this AI revises the base range of root_integer. It is clear that we +want to allow extra positive values to support modular and enumeration types, +so the range System.Min_Int .. System.Max_Int is too restrictive. root_integer +must include all the values up to System.Max_Nonbinary_Modulus - 1. + +Also, the base range of root_integer is not prevented from containing extra +(negative or positive) values, to help support nonstandard integer types. There +is no point in allowing nonstandard integer types if the implementations are +then restricted from using them for root_integer computations. There might of +course be implementation-defined restrictions in the case, but the language +should not get in the way. !ACATS Test

Questions? Ask the ACAA Technical Agent