Commit f6b5dc8e by Arnaud Charlet

[multiple changes]

2010-10-25  Robert Dewar  <dewar@adacore.com>

	* exp_ch5.adb (Expand_Predicated_Loop): Remove code for loop through
	non-static predicate, since we agree not to allow this.
	(Expand_Predicated_Loop): Properlay handle false predicate (null
	list in Static_Predicate field.
	* sem_ch13.adb (Build_Static_Predicate): Extensive changes to clean up
	handling of more general predicate forms.

2010-10-25  Robert Dewar  <dewar@adacore.com>

	* sem_ch4.adb, sem_util.adb: Minor reformatting.
	* sem_ch8.adb (Find_Selected_Component): Allow selection from instance
	of type in predicate or invariant expression.

2010-10-25  Pascal Obry  <obry@adacore.com>

	* adaint.c (__gnat_stat_to_attr): Can set the timestamp on Windows now.
	(f2t): New routine.
	(__gnat_stat): Rewrite Win32 version.

From-SVN: r165919
parent 66150d01
2010-10-25 Robert Dewar <dewar@adacore.com> 2010-10-25 Robert Dewar <dewar@adacore.com>
* exp_ch5.adb (Expand_Predicated_Loop): Remove code for loop through
non-static predicate, since we agree not to allow this.
(Expand_Predicated_Loop): Properlay handle false predicate (null
list in Static_Predicate field.
* sem_ch13.adb (Build_Static_Predicate): Extensive changes to clean up
handling of more general predicate forms.
2010-10-25 Robert Dewar <dewar@adacore.com>
* sem_ch4.adb, sem_util.adb: Minor reformatting.
* sem_ch8.adb (Find_Selected_Component): Allow selection from instance
of type in predicate or invariant expression.
2010-10-25 Pascal Obry <obry@adacore.com>
* adaint.c (__gnat_stat_to_attr): Can set the timestamp on Windows now.
(f2t): New routine.
(__gnat_stat): Rewrite Win32 version.
2010-10-25 Robert Dewar <dewar@adacore.com>
* sem_warn.adb, einfo.ads, exp_ch4.adb: Minor comment fix * sem_warn.adb, einfo.ads, exp_ch4.adb: Minor comment fix
* sem_case.adb: Comment clarification for loops through false * sem_case.adb: Comment clarification for loops through false
predicates. predicates.
......
...@@ -1112,8 +1112,6 @@ __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr) ...@@ -1112,8 +1112,6 @@ __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
attr->executable = (!ret && (statbuf.st_mode & S_IXUSR)); attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
#endif #endif
#if !defined (_WIN32) || defined (RTX)
/* on Windows requires extra system call, see __gnat_file_time_name_attr */
if (ret != 0) { if (ret != 0) {
attr->timestamp = (OS_Time)-1; attr->timestamp = (OS_Time)-1;
} else { } else {
...@@ -1124,8 +1122,6 @@ __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr) ...@@ -1124,8 +1122,6 @@ __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
attr->timestamp = (OS_Time)statbuf.st_mtime; attr->timestamp = (OS_Time)statbuf.st_mtime;
#endif #endif
} }
#endif
} }
/**************************************************************** /****************************************************************
...@@ -1345,6 +1341,19 @@ win32_filetime (HANDLE h) ...@@ -1345,6 +1341,19 @@ win32_filetime (HANDLE h)
return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset); return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
return (time_t) 0; return (time_t) 0;
} }
/* As above but starting from a FILETIME. */
static void f2t (const FILETIME *ft, time_t *t)
{
union
{
FILETIME ft_time;
unsigned long long ull_time;
} t_write;
t_write.ft_time = *ft;
*t = (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
}
#endif #endif
/* Return a GNAT time stamp given a file name. */ /* Return a GNAT time stamp given a file name. */
...@@ -1687,15 +1696,10 @@ int ...@@ -1687,15 +1696,10 @@ int
__gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf) __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
{ {
#ifdef __MINGW32__ #ifdef __MINGW32__
/* Under Windows the directory name for the stat function must not be WIN32_FILE_ATTRIBUTE_DATA fad;
terminated by a directory separator except if just after a drive name
or with UNC path without directory (only the name of the shared
resource), for example: \\computer\share\ */
TCHAR wname [GNAT_MAX_PATH_LEN + 2]; TCHAR wname [GNAT_MAX_PATH_LEN + 2];
int name_len, k; int name_len;
TCHAR last_char; BOOL res;
int dirsep_count = 0;
S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2); S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
name_len = _tcslen (wname); name_len = _tcslen (wname);
...@@ -1703,29 +1707,43 @@ __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf) ...@@ -1703,29 +1707,43 @@ __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
if (name_len > GNAT_MAX_PATH_LEN) if (name_len > GNAT_MAX_PATH_LEN)
return -1; return -1;
last_char = wname[name_len - 1]; ZeroMemory (statbuf, sizeof(GNAT_STRUCT_STAT));
while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/'))) res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad);
{
wname[name_len - 1] = _T('\0'); if (res == FALSE)
name_len--; switch (GetLastError()) {
last_char = wname[name_len - 1]; case ERROR_ACCESS_DENIED:
case ERROR_SHARING_VIOLATION:
case ERROR_LOCK_VIOLATION:
case ERROR_SHARING_BUFFER_EXCEEDED:
return EACCES;
case ERROR_BUFFER_OVERFLOW:
return ENAMETOOLONG;
case ERROR_NOT_ENOUGH_MEMORY:
return ENOMEM;
default:
return ENOENT;
} }
/* Count back-slashes. */ f2t (&fad.ftCreationTime, &statbuf->st_ctime);
f2t (&fad.ftLastWriteTime, &statbuf->st_mtime);
f2t (&fad.ftLastAccessTime, &statbuf->st_atime);
statbuf->st_size = (off_t)fad.nFileSizeLow;
for (k=0; k<name_len; k++) /* We do not have the S_IEXEC attribute, but this is not used on GNAT. */
if (wname[k] == _T('\\') || wname[k] == _T('/')) statbuf->st_mode = S_IREAD;
dirsep_count++;
/* Only a drive letter followed by ':', we must add a directory separator if (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
for the stat routine to work properly. */ statbuf->st_mode |= S_IFDIR;
if ((name_len == 2 && wname[1] == _T(':')) else
|| (name_len > 3 && wname[0] == _T('\\') && wname[1] == _T('\\') statbuf->st_mode |= S_IFREG;
&& dirsep_count == 3))
_tcscat (wname, _T("\\"));
return _tstat (wname, (struct _stat *)statbuf); if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
statbuf->st_mode |= S_IWRITE;
return 0;
#else #else
return GNAT_STAT (name, statbuf); return GNAT_STAT (name, statbuf);
......
...@@ -3001,7 +3001,7 @@ package body Exp_Ch5 is ...@@ -3001,7 +3001,7 @@ package body Exp_Ch5 is
if No (Isc) then if No (Isc) then
null; null;
-- Case of for loop (Loop_Parameter_Specfication present) -- Case of for loop (Loop_Parameter_Specification present)
-- Note: we do not have to worry about validity checking of the for loop -- Note: we do not have to worry about validity checking of the for loop
-- range bounds here, since they were frozen with constant declarations -- range bounds here, since they were frozen with constant declarations
...@@ -3215,26 +3215,20 @@ package body Exp_Ch5 is ...@@ -3215,26 +3215,20 @@ package body Exp_Ch5 is
Stmts : constant List_Id := Statements (N); Stmts : constant List_Id := Statements (N);
begin begin
-- Case of iteration over non-static predicate. In this case we -- Case of iteration over non-static predicate, should not be possible
-- generate the sequence: -- since this is not allowed by the semantics and should have been
-- caught during analysis of the loop statement.
-- for J in Ltype'First .. Ltype'Last loop
-- if Ltype_Predicate_Function (J) then
-- body;
-- end if;
-- end loop;
if No (Stat) then if No (Stat) then
raise Program_Error;
-- The analyzer already expanded the First/Last, so all we have -- If the predicate list is empty, that corresponds to a predicate of
-- to do is wrap the body within the predicate function test. -- False, in which case the loop won't run at all, and we rewrite the
-- entire loop as a null statement.
Set_Statements (N, New_List ( elsif Is_Empty_List (Stat) then
Make_If_Statement (Loc, Rewrite (N, Make_Null_Statement (Loc));
Condition => Analyze (N);
Make_Predicate_Call (Ltype, New_Occurrence_Of (Loop_Id, Loc)),
Then_Statements => Stmts)));
Analyze (First (Statements (N)));
-- For expansion over a static predicate we generate the following -- For expansion over a static predicate we generate the following
......
...@@ -94,16 +94,16 @@ package body Sem_Ch13 is ...@@ -94,16 +94,16 @@ package body Sem_Ch13 is
(Typ : Entity_Id; (Typ : Entity_Id;
Expr : Node_Id; Expr : Node_Id;
Nam : Name_Id); Nam : Name_Id);
-- Given a predicated type Typ, whose predicate expression is Expr, tests -- Given a predicated type Typ, where Typ is a discrete static subtype,
-- if Expr is a static predicate, and if so, builds the predicate range -- whose predicate expression is Expr, tests if Expr is a static predicate,
-- list. Nam is the name of the argument to the predicate function. -- and if so, builds the predicate range list. Nam is the name of the one
-- Occurrences of the type name in the predicate expression have been -- argument to the predicate function. Occurrences of the type name in the
-- replaced by identifer references to this name, which is unique, so any -- predicate expression have been replaced by identifer references to this
-- identifier with Chars matching Nam must be a reference to the type. If -- name, which is unique, so any identifier with Chars matching Nam must be
-- the predicate is non-static, this procedure returns doing nothing. If -- a reference to the type. If the predicate is non-static, this procedure
-- the predicate is static, then the corresponding predicate list is stored -- returns doing nothing. If the predicate is static, then the predicate
-- in Static_Predicate (Typ), and the Expr is rewritten as a canonicalized -- list is stored in Static_Predicate (Typ), and the Expr is rewritten as
-- membership operation. -- a canonicalized membership operation.
function Get_Alignment_Value (Expr : Node_Id) return Uint; function Get_Alignment_Value (Expr : Node_Id) return Uint;
-- Given the expression for an alignment value, returns the corresponding -- Given the expression for an alignment value, returns the corresponding
...@@ -4045,7 +4045,13 @@ package body Sem_Ch13 is ...@@ -4045,7 +4045,13 @@ package body Sem_Ch13 is
-- Deal with static predicate case -- Deal with static predicate case
Build_Static_Predicate (Typ, Expr, Object_Name); if Ekind_In (Typ, E_Enumeration_Subtype,
E_Modular_Integer_Subtype,
E_Signed_Integer_Subtype)
and then Is_Static_Subtype (Typ)
then
Build_Static_Predicate (Typ, Expr, Object_Name);
end if;
-- Build function declaration -- Build function declaration
...@@ -4115,8 +4121,15 @@ package body Sem_Ch13 is ...@@ -4115,8 +4121,15 @@ package body Sem_Ch13 is
Non_Static : exception; Non_Static : exception;
-- Raised if something non-static is found -- Raised if something non-static is found
TLo, THi : Uint; Btyp : constant Entity_Id := Base_Type (Typ);
-- Low bound and high bound values of static subtype of Typ
BLo : constant Uint := Expr_Value (Type_Low_Bound (Btyp));
BHi : constant Uint := Expr_Value (Type_High_Bound (Btyp));
-- Low bound and high bound value of base type of Typ
TLo : constant Uint := Expr_Value (Type_Low_Bound (Typ));
THi : constant Uint := Expr_Value (Type_High_Bound (Typ));
-- Low bound and high bound values of static subtype Typ
type REnt is record type REnt is record
Lo, Hi : Uint; Lo, Hi : Uint;
...@@ -4128,15 +4141,20 @@ package body Sem_Ch13 is ...@@ -4128,15 +4141,20 @@ package body Sem_Ch13 is
type RList is array (Nat range <>) of REnt; type RList is array (Nat range <>) of REnt;
-- A list of ranges. The ranges are sorted in increasing order, -- A list of ranges. The ranges are sorted in increasing order,
-- and are disjoint (there is a gap of at least one value between -- and are disjoint (there is a gap of at least one value between
-- each range in the table). -- each range in the table). A value is in the set of ranges in
-- Rlist if it lies within one of these ranges
Null_Range : constant RList := RList'(1 .. 0 => REnt'(No_Uint, No_Uint)); False_Range : constant RList :=
True_Range : RList renames Null_Range; RList'(1 .. 0 => REnt'(No_Uint, No_Uint));
-- Constant representing null list of ranges, used to represent a -- An empty set of ranges represents a range list that can never be
-- predicate of True, since there are no ranges to be satisfied. -- satisfied, since there are no ranges in which the value could lie,
-- so it does not lie in any of them. False_Range is a canonical value
-- for this empty set, but general processing should test for an Rlist
-- with length zero (see Is_False predicate), since other null ranges
-- may appear which must be treated as False.
False_Range : constant RList := RList'(1 => REnt'(Uint_1, Uint_0)); True_Range : constant RList := RList'(1 => REnt'(BLo, BHi));
-- Range representing false -- Range representing True, value must be in the base range
function "and" (Left, Right : RList) return RList; function "and" (Left, Right : RList) return RList;
-- And's together two range lists, returning a range list. This is -- And's together two range lists, returning a range list. This is
...@@ -4153,16 +4171,27 @@ package body Sem_Ch13 is ...@@ -4153,16 +4171,27 @@ package body Sem_Ch13 is
function Build_Val (V : Uint) return Node_Id; function Build_Val (V : Uint) return Node_Id;
-- Return an analyzed N_Identifier node referencing this value, suitable -- Return an analyzed N_Identifier node referencing this value, suitable
-- for use as an entry in the Static_Predicate list. -- for use as an entry in the Static_Predicate list. This node is typed
-- with the base type.
function Build_Range (Lo, Hi : Uint) return Node_Id; function Build_Range (Lo, Hi : Uint) return Node_Id;
-- Return an analyzed N_Range node referencing this range, suitable -- Return an analyzed N_Range node referencing this range, suitable
-- for use as an entry in the Static_Predicate list. -- for use as an entry in the Static_Predicate list. This node is typed
-- with the base type.
function Get_RList (Exp : Node_Id) return RList; function Get_RList (Exp : Node_Id) return RList;
-- This is a recursive routine that converts the given expression into -- This is a recursive routine that converts the given expression into
-- a list of ranges, suitable for use in building the static predicate. -- a list of ranges, suitable for use in building the static predicate.
function Is_False (R : RList) return Boolean;
pragma Inline (Is_False);
-- Returns True if the given range list is empty, and thus represents
-- a False list of ranges that can never be satsified.
function Is_True (R : RList) return Boolean;
-- Returns True if R trivially represents the True predicate by having
-- a single range from BLo to BHi.
function Is_Type_Ref (N : Node_Id) return Boolean; function Is_Type_Ref (N : Node_Id) return Boolean;
pragma Inline (Is_Type_Ref); pragma Inline (Is_Type_Ref);
-- Returns if True if N is a reference to the type for the predicate in -- Returns if True if N is a reference to the type for the predicate in
...@@ -4207,21 +4236,15 @@ package body Sem_Ch13 is ...@@ -4207,21 +4236,15 @@ package body Sem_Ch13 is
begin begin
-- If either range is True, return the other -- If either range is True, return the other
if Left = True_Range then if Is_True (Left) then
return Right; return Right;
elsif Right = True_Range then elsif Is_True (Right) then
return Left; return Left;
end if; end if;
-- If either range is False, return False -- If either range is False, return False
if Left = False_Range or else Right = False_Range then if Is_False (Left) or else Is_False (Right) then
return False_Range;
end if;
-- If either range is empty, return False
if Left'Length = 0 or else Right'Length = 0 then
return False_Range; return False_Range;
end if; end if;
...@@ -4267,18 +4290,13 @@ package body Sem_Ch13 is ...@@ -4267,18 +4290,13 @@ package body Sem_Ch13 is
SRight := SRight + 1; SRight := SRight + 1;
end if; end if;
-- If either operand is empty, that's the only entry -- Compute result by concatenating this first entry with the "and"
-- of the remaining parts of the left and right operands. Note that
-- if either of these is empty, "and" will yield empty, so that we
-- will end up with just Fent, which is what we want in that case.
if SLeft > Left'Last or else SRight > Right'Last then return
return RList'(1 => FEnt); FEnt & (Left (SLeft .. Left'Last) and Right (SRight .. Right'Last));
-- Else compute and of remaining entries and concatenate
else
return
FEnt &
(Left (SLeft .. Left'Last) and Right (SRight .. Right'Last));
end if;
end "and"; end "and";
----------- -----------
...@@ -4289,13 +4307,13 @@ package body Sem_Ch13 is ...@@ -4289,13 +4307,13 @@ package body Sem_Ch13 is
begin begin
-- Return True if False range -- Return True if False range
if Right = False_Range then if Is_False (Right) then
return True_Range; return True_Range;
end if; end if;
-- Return False if True range -- Return False if True range
if Right'Length = 0 then if Is_True (Right) then
return False_Range; return False_Range;
end if; end if;
...@@ -4340,100 +4358,76 @@ package body Sem_Ch13 is ...@@ -4340,100 +4358,76 @@ package body Sem_Ch13 is
---------- ----------
function "or" (Left, Right : RList) return RList is function "or" (Left, Right : RList) return RList is
FEnt : REnt;
-- First range of result
SLeft : Nat := Left'First;
-- Start of rest of left entries
SRight : Nat := Right'First;
-- Start of rest of right entries
begin begin
-- If either range is True, return True -- If either range is True, return True
if Left = True_Range or else Right = True_Range then if Is_True (Left) or else Is_True (Right) then
return True_Range; return True_Range;
end if; end if;
-- If either range is False, return the other -- If either range is False (empty), return the other
if Left = False_Range then if Is_False (Left) then
return Right; return Right;
elsif Right = False_Range then elsif Is_False (Right) then
return Left; return Left;
end if; end if;
-- If either operand is null, return the other one -- Initialize result first entry from left or right operand
-- depending on which starts with the lower range.
if Left'Length = 0 then if Left (SLeft).Lo < Right (SRight).Lo then
return Right; FEnt := Left (SLeft);
elsif Right'Length = 0 then SLeft := SLeft + 1;
return Left; else
FEnt := Right (SRight);
SRight := SRight + 1;
end if; end if;
-- Now we have two non-null ranges -- This loop eats ranges from left and right operands that
-- are contiguous with the first range we are gathering.
declare
FEnt : REnt;
-- First range of result
SLeft : Nat := Left'First;
-- Start of rest of left entries
SRight : Nat := Right'First; loop
-- Start of rest of right entries -- Eat first entry in left operand if contiguous or
-- overlapped by gathered first operand of result.
begin
-- Initialize result first entry from left or right operand
-- depending on which starts with the lower range.
if Left (SLeft).Lo < Right (SRight).Lo then if SLeft <= Left'Last
FEnt := Left (SLeft); and then Left (SLeft).Lo <= FEnt.Hi + 1
then
FEnt.Hi := UI_Max (FEnt.Hi, Left (SLeft).Hi);
SLeft := SLeft + 1; SLeft := SLeft + 1;
else
FEnt := Right (SRight);
SRight := SRight + 1;
end if;
-- This loop eats ranges from left and right operands that
-- are contiguous with the first range we are gathering.
loop
-- Eat first entry in left operand if contiguous or
-- overlapped by gathered first operand of result.
if SLeft <= Left'Last
and then Left (SLeft).Lo <= FEnt.Hi + 1
then
FEnt.Hi := UI_Max (FEnt.Hi, Left (SLeft).Hi);
SLeft := SLeft + 1;
-- Eat first entry in right operand if contiguous or -- Eat first entry in right operand if contiguous or
-- overlapped by gathered right operand of result. -- overlapped by gathered right operand of result.
elsif SRight <= Right'Last elsif SRight <= Right'Last
and then Right (SRight).Lo <= FEnt.Hi + 1 and then Right (SRight).Lo <= FEnt.Hi + 1
then then
FEnt.Hi := UI_Max (FEnt.Hi, Right (SRight).Hi); FEnt.Hi := UI_Max (FEnt.Hi, Right (SRight).Hi);
SRight := SRight + 1; SRight := SRight + 1;
-- All done if no more entries to eat! -- All done if no more entries to eat!
else
exit;
end if;
end loop;
-- If left operand now empty, concatenate our new entry to right
if SLeft > Left'Last then
return FEnt & Right (SRight .. Right'Last);
-- If right operand now empty, concatenate our new entry to left
elsif SRight > Right'Last then
return FEnt & Left (SLeft .. Left'Last);
-- Otherwise, compute or of what is left and concatenate
else else
return exit;
FEnt &
(Left (SLeft .. Left'Last) or Right (SRight .. Right'Last));
end if; end if;
end; end loop;
-- Obtain result as the first entry we just computed, concatenated
-- to the "or" of the remaining results (if one operand is empty,
-- this will just concatenate with the other
return
FEnt & (Left (SLeft .. Left'Last) or Right (SRight .. Right'Last));
end "or"; end "or";
----------------- -----------------
...@@ -4450,7 +4444,7 @@ package body Sem_Ch13 is ...@@ -4450,7 +4444,7 @@ package body Sem_Ch13 is
Make_Range (Loc, Make_Range (Loc,
Low_Bound => Build_Val (Lo), Low_Bound => Build_Val (Lo),
High_Bound => Build_Val (Hi)); High_Bound => Build_Val (Hi));
Set_Etype (Result, Typ); Set_Etype (Result, Btyp);
Set_Analyzed (Result); Set_Analyzed (Result);
return Result; return Result;
end if; end if;
...@@ -4470,7 +4464,7 @@ package body Sem_Ch13 is ...@@ -4470,7 +4464,7 @@ package body Sem_Ch13 is
Result := Make_Integer_Literal (Loc, Intval => V); Result := Make_Integer_Literal (Loc, Intval => V);
end if; end if;
Set_Etype (Result, Typ); Set_Etype (Result, Btyp);
Set_Is_Static_Expression (Result); Set_Is_Static_Expression (Result);
Set_Analyzed (Result); Set_Analyzed (Result);
return Result; return Result;
...@@ -4489,15 +4483,12 @@ package body Sem_Ch13 is ...@@ -4489,15 +4483,12 @@ package body Sem_Ch13 is
if Is_OK_Static_Expression (Exp) then if Is_OK_Static_Expression (Exp) then
-- For False, return impossible range, which will always fail -- For False
if Expr_Value (Exp) = 0 then if Expr_Value (Exp) = 0 then
return False_Range; return False_Range;
-- For True, null range
else else
return Null_Range; return True_Range;
end if; end if;
end if; end if;
...@@ -4566,20 +4557,20 @@ package body Sem_Ch13 is ...@@ -4566,20 +4557,20 @@ package body Sem_Ch13 is
return RList'(1 => REnt'(Val, Val)); return RList'(1 => REnt'(Val, Val));
when N_Op_Ge => when N_Op_Ge =>
return RList'(1 => REnt'(Val, THi)); return RList'(1 => REnt'(Val, BHi));
when N_Op_Gt => when N_Op_Gt =>
return RList'(1 => REnt'(Val + 1, THi)); return RList'(1 => REnt'(Val + 1, BHi));
when N_Op_Le => when N_Op_Le =>
return RList'(1 => REnt'(TLo, Val)); return RList'(1 => REnt'(BLo, Val));
when N_Op_Lt => when N_Op_Lt =>
return RList'(1 => REnt'(TLo, Val - 1)); return RList'(1 => REnt'(BLo, Val - 1));
when N_Op_Ne => when N_Op_Ne =>
return RList'(REnt'(TLo, Val - 1), return RList'(REnt'(BLo, Val - 1),
REnt'(Val + 1, THi)); REnt'(Val + 1, BHi));
when others => when others =>
raise Program_Error; raise Program_Error;
...@@ -4633,6 +4624,14 @@ package body Sem_Ch13 is ...@@ -4633,6 +4624,14 @@ package body Sem_Ch13 is
when N_Qualified_Expression => when N_Qualified_Expression =>
return Get_RList (Expression (Exp)); return Get_RList (Expression (Exp));
-- Xor operator
when N_Op_Xor =>
return (Get_RList (Left_Opnd (Exp))
and not Get_RList (Right_Opnd (Exp)))
or (Get_RList (Right_Opnd (Exp))
and not Get_RList (Left_Opnd (Exp)));
-- Any other node type is non-static -- Any other node type is non-static
when others => when others =>
...@@ -4654,6 +4653,26 @@ package body Sem_Ch13 is ...@@ -4654,6 +4653,26 @@ package body Sem_Ch13 is
end if; end if;
end Hi_Val; end Hi_Val;
--------------
-- Is_False --
--------------
function Is_False (R : RList) return Boolean is
begin
return R'Length = 0;
end Is_False;
-------------
-- Is_True --
-------------
function Is_True (R : RList) return Boolean is
begin
return R'Length = 1
and then R (R'First).Lo = BLo
and then R (R'First).Hi = BHi;
end Is_True;
----------------- -----------------
-- Is_Type_Ref -- -- Is_Type_Ref --
----------------- -----------------
...@@ -4789,22 +4808,6 @@ package body Sem_Ch13 is ...@@ -4789,22 +4808,6 @@ package body Sem_Ch13 is
-- Start of processing for Build_Static_Predicate -- Start of processing for Build_Static_Predicate
begin begin
-- Immediately non-static if our subtype is non static, or we
-- do not have an appropriate discrete subtype in the first place.
if not Ekind_In (Typ, E_Enumeration_Subtype,
E_Modular_Integer_Subtype,
E_Signed_Integer_Subtype)
or else not Is_Static_Subtype (Typ)
then
return;
end if;
-- Get bounds of the type
TLo := Expr_Value (Type_Low_Bound (Typ));
THi := Expr_Value (Type_High_Bound (Typ));
-- Now analyze the expression to see if it is a static predicate -- Now analyze the expression to see if it is a static predicate
declare declare
...@@ -4818,18 +4821,45 @@ package body Sem_Ch13 is ...@@ -4818,18 +4821,45 @@ package body Sem_Ch13 is
-- Ranges array, we just have raw ranges, these must be converted -- Ranges array, we just have raw ranges, these must be converted
-- to properly typed and analyzed static expressions or range nodes. -- to properly typed and analyzed static expressions or range nodes.
-- Note: here we limit ranges to the ranges of the subtype, so that
-- a predicate is always false for values outside the subtype. That
-- seems fine, such values are invalid anyway, and considering them
-- to fail the predicate seems allowed and friendly, and furthermore
-- simplifies processing for case statements and loops.
Plist := New_List; Plist := New_List;
for J in Ranges'Range loop for J in Ranges'Range loop
declare declare
Lo : constant Uint := Ranges (J).Lo; Lo : Uint := Ranges (J).Lo;
Hi : constant Uint := Ranges (J).Hi; Hi : Uint := Ranges (J).Hi;
begin begin
if Lo = Hi then -- Ignore completely out of range entry
Append_To (Plist, Build_Val (Lo));
if Hi < TLo or else Lo > THi then
null;
-- Otherwise process entry
else else
Append_To (Plist, Build_Range (Lo, Hi)); -- Adjust out of range value to subtype range
if Lo < TLo then
Lo := TLo;
end if;
if Hi > THi then
Hi := THi;
end if;
-- Convert range into required form
if Lo = Hi then
Append_To (Plist, Build_Val (Lo));
else
Append_To (Plist, Build_Range (Lo, Hi));
end if;
end if; end if;
end; end;
end loop; end loop;
...@@ -4865,21 +4895,12 @@ package body Sem_Ch13 is ...@@ -4865,21 +4895,12 @@ package body Sem_Ch13 is
Next (Old_Node); Next (Old_Node);
end loop; end loop;
-- If empty list, replace by True -- If empty list, replace by False
if Is_Empty_List (New_Alts) then if Is_Empty_List (New_Alts) then
Rewrite (Expr, New_Occurrence_Of (Standard_True, Loc)); Rewrite (Expr, New_Occurrence_Of (Standard_False, Loc));
-- If singleton list, replace by simple membership test
elsif List_Length (New_Alts) = 1 then
Rewrite (Expr,
Make_In (Loc,
Left_Opnd => Make_Identifier (Loc, Nam),
Right_Opnd => Relocate_Node (First (New_Alts)),
Alternatives => No_List));
-- If more than one range, replace by set membership test -- Else replace by set membership test
else else
Rewrite (Expr, Rewrite (Expr,
......
...@@ -2440,9 +2440,8 @@ package body Sem_Ch4 is ...@@ -2440,9 +2440,8 @@ package body Sem_Ch4 is
end loop; end loop;
end if; end if;
-- If not a range, it can be a subtype mark, or else it is -- If not a range, it can be a subtype mark, or else it is a degenerate
-- a degenerate membership test with a singleton value, i.e. -- membership test with a singleton value, i.e. a test for equality.
-- a test for equality.
else else
Analyze (R); Analyze (R);
...@@ -2469,8 +2468,8 @@ package body Sem_Ch4 is ...@@ -2469,8 +2468,8 @@ package body Sem_Ch4 is
return; return;
else else
-- in previous version of the language this is an error -- In previous version of the language this is an error that will
-- that will be diagnosed below. -- be diagnosed below.
Find_Type (R); Find_Type (R);
end if; end if;
......
...@@ -5479,6 +5479,11 @@ package body Sem_Ch8 is ...@@ -5479,6 +5479,11 @@ package body Sem_Ch8 is
Analyze_Selected_Component (N); Analyze_Selected_Component (N);
-- Reference to type name in predicate/invariant expression
elsif OK_To_Reference (Etype (P)) then
Analyze_Selected_Component (N);
elsif Is_Appropriate_For_Entry_Prefix (P_Type) elsif Is_Appropriate_For_Entry_Prefix (P_Type)
and then not In_Open_Scopes (P_Name) and then not In_Open_Scopes (P_Name)
and then (not Is_Concurrent_Type (Etype (P_Name)) and then (not Is_Concurrent_Type (Etype (P_Name))
...@@ -5490,10 +5495,10 @@ package body Sem_Ch8 is ...@@ -5490,10 +5495,10 @@ package body Sem_Ch8 is
Analyze_Selected_Component (N); Analyze_Selected_Component (N);
elsif (In_Open_Scopes (P_Name) elsif (In_Open_Scopes (P_Name)
and then Ekind (P_Name) /= E_Void and then Ekind (P_Name) /= E_Void
and then not Is_Overloadable (P_Name)) and then not Is_Overloadable (P_Name))
or else (Is_Concurrent_Type (Etype (P_Name)) or else (Is_Concurrent_Type (Etype (P_Name))
and then In_Open_Scopes (Etype (P_Name))) and then In_Open_Scopes (Etype (P_Name)))
then then
-- Prefix denotes an enclosing loop, block, or task, i.e. an -- Prefix denotes an enclosing loop, block, or task, i.e. an
-- enclosing construct that is not a subprogram or accept. -- enclosing construct that is not a subprogram or accept.
...@@ -5508,8 +5513,7 @@ package body Sem_Ch8 is ...@@ -5508,8 +5513,7 @@ package body Sem_Ch8 is
-- The subprogram may be a renaming (of an enclosing scope) as -- The subprogram may be a renaming (of an enclosing scope) as
-- in the case of the name of the generic within an instantiation. -- in the case of the name of the generic within an instantiation.
if (Ekind (P_Name) = E_Procedure if Ekind_In (P_Name, E_Procedure, E_Function)
or else Ekind (P_Name) = E_Function)
and then Present (Alias (P_Name)) and then Present (Alias (P_Name))
and then Is_Generic_Instance (Alias (P_Name)) and then Is_Generic_Instance (Alias (P_Name))
then then
......
...@@ -1226,7 +1226,7 @@ package body Sem_Util is ...@@ -1226,7 +1226,7 @@ package body Sem_Util is
return; return;
end if; end if;
-- Ada 2012 AI04-0144-2 : dangerous order dependence. Actuals in nested -- Ada 2012 AI04-0144-2: Dangerous order dependence. Actuals in nested
-- calls within a construct have been collected. If one of them is -- calls within a construct have been collected. If one of them is
-- writable and overlaps with another one, evaluation of the enclosing -- writable and overlaps with another one, evaluation of the enclosing
-- construct is nondeterministic. This is illegal in Ada 2012, but is -- construct is nondeterministic. This is illegal in Ada 2012, but is
...@@ -1278,6 +1278,7 @@ package body Sem_Util is ...@@ -1278,6 +1278,7 @@ package body Sem_Util is
procedure Check_Potentially_Blocking_Operation (N : Node_Id) is procedure Check_Potentially_Blocking_Operation (N : Node_Id) is
S : Entity_Id; S : Entity_Id;
begin begin
-- N is one of the potentially blocking operations listed in 9.5.1(8). -- N is one of the potentially blocking operations listed in 9.5.1(8).
-- When pragma Detect_Blocking is active, the run time will raise -- When pragma Detect_Blocking is active, the run time will raise
...@@ -1294,7 +1295,6 @@ package body Sem_Util is ...@@ -1294,7 +1295,6 @@ package body Sem_Util is
if Is_Protected_Type (S) then if Is_Protected_Type (S) then
Error_Msg_N Error_Msg_N
("potentially blocking operation in protected operation?", N); ("potentially blocking operation in protected operation?", N);
return; return;
end if; end if;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment