-- Start of processing for Discrete_Range_Check
begin
- -- Nothing to do if conversion was rewritten
+ -- Clear the Do_Range_Check flag on N if needed: this can occur when
+ -- e.g. a trivial type conversion is rewritten by its expression.
+
+ Set_Do_Range_Check (N, False);
+
+ -- Nothing more to do if conversion was rewritten
if Nkind (N) /= N_Type_Conversion then
return;
Expr := Expression (N);
+ -- Nothing to do if no range check flag set
+
+ if not Do_Range_Check (Expr) then
+ return;
+ end if;
+
+ -- Clear the Do_Range_Check flag on Expr
+
+ Set_Do_Range_Check (Expr, False);
+
-- Nothing to do if range checks suppressed
if Range_Checks_Suppressed (Target_Type) then
-- Before we do a range check, we have to deal with treating
-- a fixed-point operand as an integer. The way we do this
-- is simply to do an unchecked conversion to an appropriate
- -- integer type large enough to hold the result.
+ -- integer type with the smallest size, so that we can suppress
+ -- trivial checks.
if Is_Fixed_Point_Type (Etype (Expr)) then
- if Esize (Base_Type (Etype (Expr))) > Standard_Integer_Size then
- Ityp := Standard_Long_Long_Integer;
- else
- Ityp := Standard_Integer;
- end if;
+ Ityp := Small_Integer_Type_For
+ (Esize (Base_Type (Etype (Expr))), False);
- -- Generate a temporary with the large type to facilitate in the C
- -- backend the code generation for the unchecked conversion.
+ -- Generate a temporary with the integer type to facilitate in the
+ -- C backend the code generation for the unchecked conversion.
if Modify_Tree_For_C then
Generate_Temporary;
end if;
- Set_Do_Range_Check (Expr, False);
Rewrite (Expr, Unchecked_Convert_To (Ityp, Expr));
end if;
Tnn : Entity_Id;
begin
- -- Nothing to do if conversion was rewritten
+ -- Clear the Do_Range_Check flag on N if needed: this can occur when
+ -- e.g. a trivial type conversion is rewritten by its expression.
+
+ Set_Do_Range_Check (N, False);
+
+ -- Nothing more to do if conversion was rewritten
if Nkind (N) /= N_Type_Conversion then
return;
Expr := Expression (N);
- -- Clear the flag once for all
+ -- Clear the Do_Range_Check flag on Expr
Set_Do_Range_Check (Expr, False);
-- Nothing at all to do if conversion is to the identical type so remove
-- the conversion completely, it is useless, except that it may carry
- -- an Assignment_OK attribute, which must be propagated to the operand.
+ -- an Assignment_OK attribute, which must be propagated to the operand
+ -- and the Do_Range_Check flag on Operand should be taken into account.
if Operand_Type = Target_Type then
if Assignment_OK (N) then
end if;
Rewrite (N, Relocate_Node (Operand));
+
+ if Do_Range_Check (Operand) then
+ pragma Assert (Is_Discrete_Type (Operand_Type));
+
+ Discrete_Range_Check;
+ end if;
+
goto Done;
end if;
-- in Checks.Apply_Arithmetic_Overflow_Check, but we catch more cases in
-- the processing here. Also we still need the Checks circuit, since we
-- have to be sure not to generate junk overflow checks in the first
- -- place, since it would be trick to remove them here.
+ -- place, since it would be tricky to remove them here.
if Integer_Promotion_Possible (N) then
-- These conversions require special expansion and processing, found in
-- the Exp_Fixd package. We ignore cases where Conversion_OK is set,
-- since from a semantic point of view, these are simple integer
- -- conversions, which do not need further processing.
+ -- conversions, which do not need further processing except for the
+ -- generation of range checks, which is performed at the end of this
+ -- procedure.
elsif Is_Fixed_Point_Type (Operand_Type)
and then not Conversion_OK (N)
then
Real_Range_Check;
end if;
+
+ pragma Assert (not Do_Range_Check (Expression (N)));
end if;
-- Here at end of processing
<<Done>>
+ pragma Assert (not Do_Range_Check (N));
+
-- Apply predicate check if required. Note that we can't just call
-- Apply_Predicate_Check here, because the type looks right after
-- the conversion and it would omit the check. The Comes_From_Source
-- to apply checks required for a subtype conversion.
-- Skip these type conversion checks if universal fixed operands
- -- operands involved, since range checks are handled separately for
+ -- are involved, since range checks are handled separately for
-- these cases (in the appropriate Expand routines in unit Exp_Fixd).
if Nkind (N) = N_Type_Conversion
and then not Is_Generic_Type (Root_Type (Target_Typ))
- and then Target_Typ /= Universal_Fixed
+ and then Target_Typ /= Universal_Fixed
and then Operand_Typ /= Universal_Fixed
then
Apply_Type_Conversion_Checks (N);
(N, Target_Typ, Static_Failure_Is_Error => True);
end if;
- -- If at this stage we have a real to integer conversion, make sure that
- -- the Do_Range_Check flag is set, because such conversions in general
- -- need a range check. We only need this if expansion is off.
- -- In GNATprove mode, we only do that when converting from fixed-point
- -- (as floating-point to integer conversions are now handled in
- -- GNATprove mode).
+ -- If at this stage we have a fixed point to integer conversion, make
+ -- sure that the Do_Range_Check flag is set which is not always done
+ -- by exp_fixd.adb.
if Nkind (N) = N_Type_Conversion
- and then not Expander_Active
and then Is_Integer_Type (Target_Typ)
- and then (Is_Fixed_Point_Type (Operand_Typ)
- or else (not GNATprove_Mode
- and then Is_Floating_Point_Type (Operand_Typ)))
+ and then Is_Fixed_Point_Type (Operand_Typ)
and then not Range_Checks_Suppressed (Target_Typ)
and then not Range_Checks_Suppressed (Operand_Typ)
then