diff options
author | Arnaud Charlet <charlet@gcc.gnu.org> | 2014-02-19 12:02:48 +0100 |
---|---|---|
committer | Arnaud Charlet <charlet@gcc.gnu.org> | 2014-02-19 12:02:48 +0100 |
commit | adb252d824eac519413d0114a813543391c10592 (patch) | |
tree | c5da7428ceb37eac13e1c97e08e78fc4ac813549 /gcc | |
parent | a03670050f7aa17d56e3c2f873612343c883f980 (diff) | |
download | gcc-adb252d824eac519413d0114a813543391c10592.zip gcc-adb252d824eac519413d0114a813543391c10592.tar.gz gcc-adb252d824eac519413d0114a813543391c10592.tar.bz2 |
[multiple changes]
2014-02-19 Robert Dewar <dewar@adacore.com>
* exp_attr.adb (Expand_Min_Max_Attribute): Use Insert_Declaration
(Expand_Min_Max_Attribute): Use Matching_Standard_Type.
* exp_ch4.adb (Expand_N_Expression_With_Actions): Remove special
handling for the case of Modify_Tree_For_C, this approach did
not work.
* exp_util.adb (Matching_Standard_Type): New function
(Side_Effect_Free): New top level functions (from
Remove_Side_Effects).
* exp_util.ads (Side_Effect_Free): New top level functions
(moved from body).
* sinfo.ads: Minor comment updates.
2014-02-19 Ed Schonberg <schonberg@adacore.com>
* exp_ch6.adb (Expand_Simple_Function_Return): If return
type is unconstrained and uses the secondary stack, mark the
enclosing function accordingly, to ensure that the value is not
prematurely removed.
2014-02-19 Hristian Kirtchev <kirtchev@adacore.com>
* par.adb Alphabetize the routines in Par.Sync.
(Resync_Past_Malformed_Aspect): New routine.
* par-ch13.adb (Get_Aspect_Specifications): Alphabetize local
variables. Code and comment reformatting. Detect missing
parentheses on aspects [Refined_]Global and [Refined_]Depends
with a non-null definition.
* par-sync.adb: Alphabetize all routines in this separate unit.
(Resync_Past_Malformed_Aspect): New routine.
From-SVN: r207890
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ada/ChangeLog | 32 | ||||
-rw-r--r-- | gcc/ada/exp_attr.adb | 70 | ||||
-rw-r--r-- | gcc/ada/exp_ch4.adb | 75 | ||||
-rw-r--r-- | gcc/ada/exp_ch6.adb | 7 | ||||
-rw-r--r-- | gcc/ada/exp_util.adb | 884 | ||||
-rw-r--r-- | gcc/ada/exp_util.ads | 33 | ||||
-rw-r--r-- | gcc/ada/par-ch13.adb | 220 | ||||
-rw-r--r-- | gcc/ada/par-sync.adb | 166 | ||||
-rw-r--r-- | gcc/ada/par.adb | 31 | ||||
-rw-r--r-- | gcc/ada/sinfo.ads | 12 |
10 files changed, 862 insertions, 668 deletions
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 243878d..e8f0c63 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,37 @@ 2014-02-19 Robert Dewar <dewar@adacore.com> + * exp_attr.adb (Expand_Min_Max_Attribute): Use Insert_Declaration + (Expand_Min_Max_Attribute): Use Matching_Standard_Type. + * exp_ch4.adb (Expand_N_Expression_With_Actions): Remove special + handling for the case of Modify_Tree_For_C, this approach did + not work. + * exp_util.adb (Matching_Standard_Type): New function + (Side_Effect_Free): New top level functions (from + Remove_Side_Effects). + * exp_util.ads (Side_Effect_Free): New top level functions + (moved from body). + * sinfo.ads: Minor comment updates. + +2014-02-19 Ed Schonberg <schonberg@adacore.com> + + * exp_ch6.adb (Expand_Simple_Function_Return): If return + type is unconstrained and uses the secondary stack, mark the + enclosing function accordingly, to ensure that the value is not + prematurely removed. + +2014-02-19 Hristian Kirtchev <kirtchev@adacore.com> + + * par.adb Alphabetize the routines in Par.Sync. + (Resync_Past_Malformed_Aspect): New routine. + * par-ch13.adb (Get_Aspect_Specifications): Alphabetize local + variables. Code and comment reformatting. Detect missing + parentheses on aspects [Refined_]Global and [Refined_]Depends + with a non-null definition. + * par-sync.adb: Alphabetize all routines in this separate unit. + (Resync_Past_Malformed_Aspect): New routine. + +2014-02-19 Robert Dewar <dewar@adacore.com> + * sem_eval.ads, sem_eval.adb (Subtypes_Statically_Match): Return False if Esize values do not match. diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb index 21472b6..2e370ac 100644 --- a/gcc/ada/exp_attr.adb +++ b/gcc/ada/exp_attr.adb @@ -1062,8 +1062,6 @@ package body Exp_Attr is Expr : constant Node_Id := First (Expressions (N)); Left : constant Node_Id := Relocate_Node (Expr); Right : constant Node_Id := Relocate_Node (Next (Expr)); - Ltyp : constant Entity_Id := Etype (Left); - Rtyp : constant Entity_Id := Etype (Right); function Make_Compare (Left, Right : Node_Id) return Node_Id; -- Returns Left >= Right for Max, Left <= Right for Min @@ -1090,12 +1088,12 @@ package body Exp_Attr is -- Start of processing for Min_Max begin - -- If both Left and Right are simple entity names, then we can - -- just use Duplicate_Expr to duplicate the references and return + -- If both Left and Right are side effect free, then we can just + -- use Duplicate_Expr to duplicate the references and return -- (if Left >=|<= Right then Left else Right) - if Is_Entity_Name (Left) and then Is_Entity_Name (Right) then + if Side_Effect_Free (Left) and then Side_Effect_Free (Right) then Rewrite (N, Make_If_Expression (Loc, Expressions => New_List ( @@ -1103,35 +1101,57 @@ package body Exp_Attr is Duplicate_Subexpr_No_Checks (Left), Duplicate_Subexpr_No_Checks (Right)))); - -- Otherwise we wrap things in an expression with actions. You - -- might think we could just use the approach above, but there - -- are problems, in particular with escaped discriminants. In - -- this case we generate: + -- Otherwise we generate declarations to capture the values. We + -- can't put these declarations inside the if expression, since + -- we could end up with an N_Expression_With_Actions which has + -- declarations in the actions, forbidden for Modify_Tree_For_C. + + -- The translation is + + -- T1 : styp; -- inserted high up in tree + -- T2 : styp; -- inserted high up in tree -- do - -- T1 : constant typ := Left; - -- T2 : constant typ := Right; + -- T1 := styp!(Left); + -- T2 := styp!(Right); -- in - -- (if T1 >=|<= T2 then T1 else T2) + -- (if T1 >=|<= T2 then typ!(T1) else typ!(T2)) -- end; + -- We insert the T1,T2 declarations with Insert_Declaration which + -- inserts these declarations high up in the tree unconditionally. + -- This is safe since no code is associated with the declarations. + -- Here styp is a standard type whose Esize matches the size of + -- our type. We do this because the actual type may be a result of + -- some local declaration which would not be visible at the point + -- where we insert the declarations of T1 and T2. + else declare - T1 : constant Entity_Id := Make_Temporary (Loc, 'T', Left); - T2 : constant Entity_Id := Make_Temporary (Loc, 'T', Left); + T1 : constant Entity_Id := Make_Temporary (Loc, 'T', Left); + T2 : constant Entity_Id := Make_Temporary (Loc, 'T', Left); + Styp : constant Entity_Id := Matching_Standard_Type (Typ); begin + Insert_Declaration (N, + Make_Object_Declaration (Loc, + Defining_Identifier => T1, + Object_Definition => New_Occurrence_Of (Styp, Loc))); + + Insert_Declaration (N, + Make_Object_Declaration (Loc, + Defining_Identifier => T2, + Object_Definition => New_Occurrence_Of (Styp, Loc))); + Rewrite (N, Make_Expression_With_Actions (Loc, Actions => New_List ( - Make_Object_Declaration (Loc, - Defining_Identifier => T1, - Object_Definition => New_Occurrence_Of (Ltyp, Loc), - Expression => Left), - Make_Object_Declaration (Loc, - Defining_Identifier => T2, - Object_Definition => New_Occurrence_Of (Rtyp, Loc), - Expression => Right)), + Make_Assignment_Statement (Loc, + Name => New_Occurrence_Of (T1, Loc), + Expression => Unchecked_Convert_To (Styp, Left)), + Make_Assignment_Statement (Loc, + Name => New_Occurrence_Of (T2, Loc), + Expression => Unchecked_Convert_To (Styp, Right))), Expression => Make_If_Expression (Loc, @@ -1139,8 +1159,10 @@ package body Exp_Attr is Make_Compare (New_Occurrence_Of (T1, Loc), New_Occurrence_Of (T2, Loc)), - New_Occurrence_Of (T1, Loc), - New_Occurrence_Of (T2, Loc))))); + Unchecked_Convert_To (Typ, + New_Occurrence_Of (T1, Loc)), + Unchecked_Convert_To (Typ, + New_Occurrence_Of (T2, Loc)))))); end; end if; diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb index b9ff98c..512ebd8 100644 --- a/gcc/ada/exp_ch4.adb +++ b/gcc/ada/exp_ch4.adb @@ -5067,14 +5067,6 @@ package body Exp_Ch4 is -------------------------------------- procedure Expand_N_Expression_With_Actions (N : Node_Id) is - procedure Insert_Declaration (Decl : Node_Id); - -- This is like Insert_Action, but inserts outside the expression in - -- which N appears. This is needed, because otherwise we can end up - -- inserting a declaration in the actions of a short circuit, and that - -- will not do, because that's likely where we (the expression with - -- actions) node came from the first place. We are only inserting a - -- declaration with no side effects, so it is harmless (and needed) - -- to insert at a higher point in the tree. function Process_Action (Act : Node_Id) return Traverse_Result; -- Inspect and process a single action of an expression_with_actions for @@ -5082,27 +5074,6 @@ package body Exp_Ch4 is -- generates code to clean them up when the context of the expression is -- evaluated or elaborated. - ------------------------ - -- Insert_Declaration -- - ------------------------ - - procedure Insert_Declaration (Decl : Node_Id) is - P : Node_Id; - - begin - -- Climb out of the current expression - - P := Decl; - loop - exit when Nkind (Parent (P)) not in N_Subexpr; - P := Parent (P); - end loop; - - -- Now do the insertion - - Insert_Action (P, Decl); - end Insert_Declaration; - -------------------- -- Process_Action -- -------------------- @@ -5135,11 +5106,7 @@ package body Exp_Ch4 is -- Local variables - Loc : Source_Ptr; Act : Node_Id; - Def : Entity_Id; - Exp : Node_Id; - Nxt : Node_Id; -- Start of processing for Expand_N_Expression_With_Actions @@ -5152,48 +5119,6 @@ package body Exp_Ch4 is Next (Act); end loop; - -- In Modify_Tree_For_C, we have trouble in C with object declarations - -- in the actions list (expressions are fine). So if we have an object - -- declaration, insert it higher in the tree, if necessary replacing it - -- with an assignment to capture initialization. - - if Modify_Tree_For_C then - Act := First (Actions (N)); - while Present (Act) loop - if Nkind (Act) = N_Object_Declaration then - Def := Defining_Identifier (Act); - Exp := Expression (Act); - Set_Constant_Present (Act, False); - Set_Expression (Act, Empty); - Insert_Declaration (Relocate_Node (Act)); - - Loc := Sloc (Act); - - -- Expression present, rewrite as assignment, get next action - - if Present (Exp) then - Rewrite (Act, - Make_Assignment_Statement (Loc, - Name => New_Occurrence_Of (Def, Loc), - Expression => Exp)); - Next (Act); - - -- No expression, remove action and move to next - - else - Nxt := Next (Act); - Remove (Act); - Act := Nxt; - end if; - - -- Not an object declaration, move to next action - - else - Next (Act); - end if; - end loop; - end if; - -- Deal with case where there are no actions. In this case we simply -- rewrite the node with its expression since we don't need the actions -- and the specification of this node does not allow a null action list. diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb index 3908584..e1c4722 100644 --- a/gcc/ada/exp_ch6.adb +++ b/gcc/ada/exp_ch6.adb @@ -7834,6 +7834,13 @@ package body Exp_Ch6 is Set_Sec_Stack_Needed_For_Return (S, True); S := Enclosing_Dynamic_Scope (S); end loop; + + -- The enclosing function itself must be marked as well, to + -- prevent premature secondary stack cleanup. + + if Ekind (S) = E_Function then + Set_Sec_Stack_Needed_For_Return (Scope_Id); + end if; end; -- Optimize the case where the result is a function call. In this diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb index 27559d7..251e919 100644 --- a/gcc/ada/exp_util.adb +++ b/gcc/ada/exp_util.adb @@ -3962,11 +3962,13 @@ package body Exp_Util is -- Climb until we find a procedure or a package - P := Parent (N); + P := N; loop + pragma Assert (Present (Parent (P))); + P := Parent (P); + if Is_List_Member (P) then exit when Nkind_In (Parent (P), N_Package_Specification, - N_Package_Body, N_Subprogram_Body); -- Special handling for handled sequence of statements, we must @@ -3977,8 +3979,6 @@ package body Exp_Util is exit; end if; end if; - - P := Parent (P); end loop; -- Now do the insertion @@ -5970,7 +5970,7 @@ package body Exp_Util is Siz : constant Uint := Esize (Typ); begin - -- Float-point cases + -- Floating-point cases if Is_Floating_Point_Type (Typ) then if Siz <= Esize (Standard_Short_Float) then @@ -5987,7 +5987,7 @@ package body Exp_Util is -- Integer cases (includes fixed-point types) - -- Unsigned cases (includes normal enumeration types) + -- Unsigned integer cases (includes normal enumeration types) elsif Is_Unsigned_Type (Typ) then if Siz <= Esize (Standard_Short_Short_Unsigned) then @@ -6004,7 +6004,7 @@ package body Exp_Util is raise Program_Error; end if; - -- Signed cases + -- Signed integer cases else if Siz <= Esize (Standard_Short_Short_Integer) then @@ -6635,435 +6635,6 @@ package body Exp_Util is Ref_Type : Entity_Id; Res : Node_Id; - function Side_Effect_Free (N : Node_Id) return Boolean; - -- Determines if the tree N represents an expression that is known not - -- to have side effects, and for which no processing is required. - - function Side_Effect_Free (L : List_Id) return Boolean; - -- Determines if all elements of the list L are side effect free - - function Safe_Prefixed_Reference (N : Node_Id) return Boolean; - -- The argument N is a construct where the Prefix is dereferenced if it - -- is an access type and the result is a variable. The call returns True - -- if the construct is side effect free (not considering side effects in - -- other than the prefix which are to be tested by the caller). - - function Within_In_Parameter (N : Node_Id) return Boolean; - -- Determines if N is a subcomponent of a composite in-parameter. If so, - -- N is not side-effect free when the actual is global and modifiable - -- indirectly from within a subprogram, because it may be passed by - -- reference. The front-end must be conservative here and assume that - -- this may happen with any array or record type. On the other hand, we - -- cannot create temporaries for all expressions for which this - -- condition is true, for various reasons that might require clearing up - -- ??? For example, discriminant references that appear out of place, or - -- spurious type errors with class-wide expressions. As a result, we - -- limit the transformation to loop bounds, which is so far the only - -- case that requires it. - - ----------------------------- - -- Safe_Prefixed_Reference -- - ----------------------------- - - function Safe_Prefixed_Reference (N : Node_Id) return Boolean is - begin - -- If prefix is not side effect free, definitely not safe - - if not Side_Effect_Free (Prefix (N)) then - return False; - - -- If the prefix is of an access type that is not access-to-constant, - -- then this construct is a variable reference, which means it is to - -- be considered to have side effects if Variable_Ref is set True. - - elsif Is_Access_Type (Etype (Prefix (N))) - and then not Is_Access_Constant (Etype (Prefix (N))) - and then Variable_Ref - then - -- Exception is a prefix that is the result of a previous removal - -- of side-effects. - - return Is_Entity_Name (Prefix (N)) - and then not Comes_From_Source (Prefix (N)) - and then Ekind (Entity (Prefix (N))) = E_Constant - and then Is_Internal_Name (Chars (Entity (Prefix (N)))); - - -- If the prefix is an explicit dereference then this construct is a - -- variable reference, which means it is to be considered to have - -- side effects if Variable_Ref is True. - - -- We do NOT exclude dereferences of access-to-constant types because - -- we handle them as constant view of variables. - - elsif Nkind (Prefix (N)) = N_Explicit_Dereference - and then Variable_Ref - then - return False; - - -- Note: The following test is the simplest way of solving a complex - -- problem uncovered by the following test (Side effect on loop bound - -- that is a subcomponent of a global variable: - - -- with Text_Io; use Text_Io; - -- procedure Tloop is - -- type X is - -- record - -- V : Natural := 4; - -- S : String (1..5) := (others => 'a'); - -- end record; - -- X1 : X; - - -- procedure Modi; - - -- generic - -- with procedure Action; - -- procedure Loop_G (Arg : X; Msg : String) - - -- procedure Loop_G (Arg : X; Msg : String) is - -- begin - -- Put_Line ("begin loop_g " & Msg & " will loop till: " - -- & Natural'Image (Arg.V)); - -- for Index in 1 .. Arg.V loop - -- Text_Io.Put_Line - -- (Natural'Image (Index) & " " & Arg.S (Index)); - -- if Index > 2 then - -- Modi; - -- end if; - -- end loop; - -- Put_Line ("end loop_g " & Msg); - -- end; - - -- procedure Loop1 is new Loop_G (Modi); - -- procedure Modi is - -- begin - -- X1.V := 1; - -- Loop1 (X1, "from modi"); - -- end; - -- - -- begin - -- Loop1 (X1, "initial"); - -- end; - - -- The output of the above program should be: - - -- begin loop_g initial will loop till: 4 - -- 1 a - -- 2 a - -- 3 a - -- begin loop_g from modi will loop till: 1 - -- 1 a - -- end loop_g from modi - -- 4 a - -- begin loop_g from modi will loop till: 1 - -- 1 a - -- end loop_g from modi - -- end loop_g initial - - -- If a loop bound is a subcomponent of a global variable, a - -- modification of that variable within the loop may incorrectly - -- affect the execution of the loop. - - elsif Nkind (Parent (Parent (N))) = N_Loop_Parameter_Specification - and then Within_In_Parameter (Prefix (N)) - and then Variable_Ref - then - return False; - - -- All other cases are side effect free - - else - return True; - end if; - end Safe_Prefixed_Reference; - - ---------------------- - -- Side_Effect_Free -- - ---------------------- - - function Side_Effect_Free (N : Node_Id) return Boolean is - begin - -- Note on checks that could raise Constraint_Error. Strictly, if we - -- take advantage of 11.6, these checks do not count as side effects. - -- However, we would prefer to consider that they are side effects, - -- since the backend CSE does not work very well on expressions which - -- can raise Constraint_Error. On the other hand if we don't consider - -- them to be side effect free, then we get some awkward expansions - -- in -gnato mode, resulting in code insertions at a point where we - -- do not have a clear model for performing the insertions. - - -- Special handling for entity names - - if Is_Entity_Name (N) then - - -- Variables are considered to be a side effect if Variable_Ref - -- is set or if we have a volatile reference and Name_Req is off. - -- If Name_Req is True then we can't help returning a name which - -- effectively allows multiple references in any case. - - if Is_Variable (N, Use_Original_Node => False) then - return not Variable_Ref - and then (not Is_Volatile_Reference (N) or else Name_Req); - - -- Any other entity (e.g. a subtype name) is definitely side - -- effect free. - - else - return True; - end if; - - -- A value known at compile time is always side effect free - - elsif Compile_Time_Known_Value (N) then - return True; - - -- A variable renaming is not side-effect free, because the renaming - -- will function like a macro in the front-end in some cases, and an - -- assignment can modify the component designated by N, so we need to - -- create a temporary for it. - - -- The guard testing for Entity being present is needed at least in - -- the case of rewritten predicate expressions, and may well also be - -- appropriate elsewhere. Obviously we can't go testing the entity - -- field if it does not exist, so it's reasonable to say that this is - -- not the renaming case if it does not exist. - - elsif Is_Entity_Name (Original_Node (N)) - and then Present (Entity (Original_Node (N))) - and then Is_Renaming_Of_Object (Entity (Original_Node (N))) - and then Ekind (Entity (Original_Node (N))) /= E_Constant - then - declare - RO : constant Node_Id := - Renamed_Object (Entity (Original_Node (N))); - - begin - -- If the renamed object is an indexed component, or an - -- explicit dereference, then the designated object could - -- be modified by an assignment. - - if Nkind_In (RO, N_Indexed_Component, - N_Explicit_Dereference) - then - return False; - - -- A selected component must have a safe prefix - - elsif Nkind (RO) = N_Selected_Component then - return Safe_Prefixed_Reference (RO); - - -- In all other cases, designated object cannot be changed so - -- we are side effect free. - - else - return True; - end if; - end; - - -- Remove_Side_Effects generates an object renaming declaration to - -- capture the expression of a class-wide expression. In VM targets - -- the frontend performs no expansion for dispatching calls to - -- class- wide types since they are handled by the VM. Hence, we must - -- locate here if this node corresponds to a previous invocation of - -- Remove_Side_Effects to avoid a never ending loop in the frontend. - - elsif VM_Target /= No_VM - and then not Comes_From_Source (N) - and then Nkind (Parent (N)) = N_Object_Renaming_Declaration - and then Is_Class_Wide_Type (Etype (N)) - then - return True; - end if; - - -- For other than entity names and compile time known values, - -- check the node kind for special processing. - - case Nkind (N) is - - -- An attribute reference is side effect free if its expressions - -- are side effect free and its prefix is side effect free or - -- is an entity reference. - - -- Is this right? what about x'first where x is a variable??? - - when N_Attribute_Reference => - return Side_Effect_Free (Expressions (N)) - and then Attribute_Name (N) /= Name_Input - and then (Is_Entity_Name (Prefix (N)) - or else Side_Effect_Free (Prefix (N))); - - -- A binary operator is side effect free if and both operands are - -- side effect free. For this purpose binary operators include - -- membership tests and short circuit forms. - - when N_Binary_Op | N_Membership_Test | N_Short_Circuit => - return Side_Effect_Free (Left_Opnd (N)) - and then - Side_Effect_Free (Right_Opnd (N)); - - -- An explicit dereference is side effect free only if it is - -- a side effect free prefixed reference. - - when N_Explicit_Dereference => - return Safe_Prefixed_Reference (N); - - -- An expression with action is side effect free if its expression - -- is side effect free and it has no actions. - - when N_Expression_With_Actions => - return Is_Empty_List (Actions (N)) - and then - Side_Effect_Free (Expression (N)); - - -- A call to _rep_to_pos is side effect free, since we generate - -- this pure function call ourselves. Moreover it is critically - -- important to make this exception, since otherwise we can have - -- discriminants in array components which don't look side effect - -- free in the case of an array whose index type is an enumeration - -- type with an enumeration rep clause. - - -- All other function calls are not side effect free - - when N_Function_Call => - return Nkind (Name (N)) = N_Identifier - and then Is_TSS (Name (N), TSS_Rep_To_Pos) - and then - Side_Effect_Free (First (Parameter_Associations (N))); - - -- An indexed component is side effect free if it is a side - -- effect free prefixed reference and all the indexing - -- expressions are side effect free. - - when N_Indexed_Component => - return Side_Effect_Free (Expressions (N)) - and then Safe_Prefixed_Reference (N); - - -- A type qualification is side effect free if the expression - -- is side effect free. - - when N_Qualified_Expression => - return Side_Effect_Free (Expression (N)); - - -- A selected component is side effect free only if it is a side - -- effect free prefixed reference. If it designates a component - -- with a rep. clause it must be treated has having a potential - -- side effect, because it may be modified through a renaming, and - -- a subsequent use of the renaming as a macro will yield the - -- wrong value. This complex interaction between renaming and - -- removing side effects is a reminder that the latter has become - -- a headache to maintain, and that it should be removed in favor - -- of the gcc mechanism to capture values ??? - - when N_Selected_Component => - if Nkind (Parent (N)) = N_Explicit_Dereference - and then Has_Non_Standard_Rep (Designated_Type (Etype (N))) - then - return False; - else - return Safe_Prefixed_Reference (N); - end if; - - -- A range is side effect free if the bounds are side effect free - - when N_Range => - return Side_Effect_Free (Low_Bound (N)) - and then Side_Effect_Free (High_Bound (N)); - - -- A slice is side effect free if it is a side effect free - -- prefixed reference and the bounds are side effect free. - - when N_Slice => - return Side_Effect_Free (Discrete_Range (N)) - and then Safe_Prefixed_Reference (N); - - -- A type conversion is side effect free if the expression to be - -- converted is side effect free. - - when N_Type_Conversion => - return Side_Effect_Free (Expression (N)); - - -- A unary operator is side effect free if the operand - -- is side effect free. - - when N_Unary_Op => - return Side_Effect_Free (Right_Opnd (N)); - - -- An unchecked type conversion is side effect free only if it - -- is safe and its argument is side effect free. - - when N_Unchecked_Type_Conversion => - return Safe_Unchecked_Type_Conversion (N) - and then Side_Effect_Free (Expression (N)); - - -- An unchecked expression is side effect free if its expression - -- is side effect free. - - when N_Unchecked_Expression => - return Side_Effect_Free (Expression (N)); - - -- A literal is side effect free - - when N_Character_Literal | - N_Integer_Literal | - N_Real_Literal | - N_String_Literal => - return True; - - -- We consider that anything else has side effects. This is a bit - -- crude, but we are pretty close for most common cases, and we - -- are certainly correct (i.e. we never return True when the - -- answer should be False). - - when others => - return False; - end case; - end Side_Effect_Free; - - -- A list is side effect free if all elements of the list are side - -- effect free. - - function Side_Effect_Free (L : List_Id) return Boolean is - N : Node_Id; - - begin - if L = No_List or else L = Error_List then - return True; - - else - N := First (L); - while Present (N) loop - if not Side_Effect_Free (N) then - return False; - else - Next (N); - end if; - end loop; - - return True; - end if; - end Side_Effect_Free; - - ------------------------- - -- Within_In_Parameter -- - ------------------------- - - function Within_In_Parameter (N : Node_Id) return Boolean is - begin - if not Comes_From_Source (N) then - return False; - - elsif Is_Entity_Name (N) then - return Ekind (Entity (N)) = E_In_Parameter; - - elsif Nkind_In (N, N_Indexed_Component, N_Selected_Component) then - return Within_In_Parameter (Prefix (N)); - - else - return False; - end if; - end Within_In_Parameter; - - -- Start of processing for Remove_Side_Effects - begin -- Handle cases in which there is nothing to do. In GNATprove mode, -- removal of side effects is useful for the light expansion of @@ -7085,7 +6656,7 @@ package body Exp_Util is -- No action needed for side-effect free expressions - elsif Side_Effect_Free (Exp) then + elsif Side_Effect_Free (Exp, Name_Req, Variable_Ref) then return; end if; @@ -7099,7 +6670,7 @@ package body Exp_Util is -- If it is a scalar type and we need to capture the value, just make -- a copy. Likewise for a function call, an attribute reference, a -- conditional expression, an allocator, or an operator. And if we have - -- a volatile reference and Name_Req is not set (see comments above for + -- a volatile reference and Name_Req is not set (see comments for -- Side_Effect_Free). if Is_Elementary_Type (Exp_Type) @@ -7223,7 +6794,7 @@ package body Exp_Util is -- approach would generate an illegal access value (an access value -- cannot designate such an object - see Analyze_Reference). We skip -- using this scheme if we have an object of a volatile type and we do - -- not have Name_Req set true (see comments above for Side_Effect_Free). + -- not have Name_Req set true (see comments for Side_Effect_Free). -- In Ada 2012 a qualified expression is an object, but for purposes of -- removing side effects it still need to be transformed into a separate @@ -8095,6 +7666,441 @@ package body Exp_Util is end if; end Set_Renamed_Subprogram; + ---------------------- + -- Side_Effect_Free -- + ---------------------- + + function Side_Effect_Free + (N : Node_Id; + Name_Req : Boolean := False; + Variable_Ref : Boolean := False) return Boolean + is + function Safe_Prefixed_Reference (N : Node_Id) return Boolean; + -- The argument N is a construct where the Prefix is dereferenced if it + -- is an access type and the result is a variable. The call returns True + -- if the construct is side effect free (not considering side effects in + -- other than the prefix which are to be tested by the caller). + + function Within_In_Parameter (N : Node_Id) return Boolean; + -- Determines if N is a subcomponent of a composite in-parameter. If so, + -- N is not side-effect free when the actual is global and modifiable + -- indirectly from within a subprogram, because it may be passed by + -- reference. The front-end must be conservative here and assume that + -- this may happen with any array or record type. On the other hand, we + -- cannot create temporaries for all expressions for which this + -- condition is true, for various reasons that might require clearing up + -- ??? For example, discriminant references that appear out of place, or + -- spurious type errors with class-wide expressions. As a result, we + -- limit the transformation to loop bounds, which is so far the only + -- case that requires it. + + ----------------------------- + -- Safe_Prefixed_Reference -- + ----------------------------- + + function Safe_Prefixed_Reference (N : Node_Id) return Boolean is + begin + -- If prefix is not side effect free, definitely not safe + + if not Side_Effect_Free (Prefix (N), Name_Req, Variable_Ref) then + return False; + + -- If the prefix is of an access type that is not access-to-constant, + -- then this construct is a variable reference, which means it is to + -- be considered to have side effects if Variable_Ref is set True. + + elsif Is_Access_Type (Etype (Prefix (N))) + and then not Is_Access_Constant (Etype (Prefix (N))) + and then Variable_Ref + then + -- Exception is a prefix that is the result of a previous removal + -- of side-effects. + + return Is_Entity_Name (Prefix (N)) + and then not Comes_From_Source (Prefix (N)) + and then Ekind (Entity (Prefix (N))) = E_Constant + and then Is_Internal_Name (Chars (Entity (Prefix (N)))); + + -- If the prefix is an explicit dereference then this construct is a + -- variable reference, which means it is to be considered to have + -- side effects if Variable_Ref is True. + + -- We do NOT exclude dereferences of access-to-constant types because + -- we handle them as constant view of variables. + + elsif Nkind (Prefix (N)) = N_Explicit_Dereference + and then Variable_Ref + then + return False; + + -- Note: The following test is the simplest way of solving a complex + -- problem uncovered by the following test (Side effect on loop bound + -- that is a subcomponent of a global variable: + + -- with Text_Io; use Text_Io; + -- procedure Tloop is + -- type X is + -- record + -- V : Natural := 4; + -- S : String (1..5) := (others => 'a'); + -- end record; + -- X1 : X; + + -- procedure Modi; + + -- generic + -- with procedure Action; + -- procedure Loop_G (Arg : X; Msg : String) + + -- procedure Loop_G (Arg : X; Msg : String) is + -- begin + -- Put_Line ("begin loop_g " & Msg & " will loop till: " + -- & Natural'Image (Arg.V)); + -- for Index in 1 .. Arg.V loop + -- Text_Io.Put_Line + -- (Natural'Image (Index) & " " & Arg.S (Index)); + -- if Index > 2 then + -- Modi; + -- end if; + -- end loop; + -- Put_Line ("end loop_g " & Msg); + -- end; + + -- procedure Loop1 is new Loop_G (Modi); + -- procedure Modi is + -- begin + -- X1.V := 1; + -- Loop1 (X1, "from modi"); + -- end; + -- + -- begin + -- Loop1 (X1, "initial"); + -- end; + + -- The output of the above program should be: + + -- begin loop_g initial will loop till: 4 + -- 1 a + -- 2 a + -- 3 a + -- begin loop_g from modi will loop till: 1 + -- 1 a + -- end loop_g from modi + -- 4 a + -- begin loop_g from modi will loop till: 1 + -- 1 a + -- end loop_g from modi + -- end loop_g initial + + -- If a loop bound is a subcomponent of a global variable, a + -- modification of that variable within the loop may incorrectly + -- affect the execution of the loop. + + elsif Nkind (Parent (Parent (N))) = N_Loop_Parameter_Specification + and then Within_In_Parameter (Prefix (N)) + and then Variable_Ref + then + return False; + + -- All other cases are side effect free + + else + return True; + end if; + end Safe_Prefixed_Reference; + + ------------------------- + -- Within_In_Parameter -- + ------------------------- + + function Within_In_Parameter (N : Node_Id) return Boolean is + begin + if not Comes_From_Source (N) then + return False; + + elsif Is_Entity_Name (N) then + return Ekind (Entity (N)) = E_In_Parameter; + + elsif Nkind_In (N, N_Indexed_Component, N_Selected_Component) then + return Within_In_Parameter (Prefix (N)); + + else + return False; + end if; + end Within_In_Parameter; + + -- Start of processing for Side_Effect_Free + + begin + -- Note on checks that could raise Constraint_Error. Strictly, if we + -- take advantage of 11.6, these checks do not count as side effects. + -- However, we would prefer to consider that they are side effects, + -- since the backend CSE does not work very well on expressions which + -- can raise Constraint_Error. On the other hand if we don't consider + -- them to be side effect free, then we get some awkward expansions + -- in -gnato mode, resulting in code insertions at a point where we + -- do not have a clear model for performing the insertions. + + -- Special handling for entity names + + if Is_Entity_Name (N) then + + -- Variables are considered to be a side effect if Variable_Ref + -- is set or if we have a volatile reference and Name_Req is off. + -- If Name_Req is True then we can't help returning a name which + -- effectively allows multiple references in any case. + + if Is_Variable (N, Use_Original_Node => False) then + return not Variable_Ref + and then (not Is_Volatile_Reference (N) or else Name_Req); + + -- Any other entity (e.g. a subtype name) is definitely side + -- effect free. + + else + return True; + end if; + + -- A value known at compile time is always side effect free + + elsif Compile_Time_Known_Value (N) then + return True; + + -- A variable renaming is not side-effect free, because the renaming + -- will function like a macro in the front-end in some cases, and an + -- assignment can modify the component designated by N, so we need to + -- create a temporary for it. + + -- The guard testing for Entity being present is needed at least in + -- the case of rewritten predicate expressions, and may well also be + -- appropriate elsewhere. Obviously we can't go testing the entity + -- field if it does not exist, so it's reasonable to say that this is + -- not the renaming case if it does not exist. + + elsif Is_Entity_Name (Original_Node (N)) + and then Present (Entity (Original_Node (N))) + and then Is_Renaming_Of_Object (Entity (Original_Node (N))) + and then Ekind (Entity (Original_Node (N))) /= E_Constant + then + declare + RO : constant Node_Id := + Renamed_Object (Entity (Original_Node (N))); + + begin + -- If the renamed object is an indexed component, or an + -- explicit dereference, then the designated object could + -- be modified by an assignment. + + if Nkind_In (RO, N_Indexed_Component, + N_Explicit_Dereference) + then + return False; + + -- A selected component must have a safe prefix + + elsif Nkind (RO) = N_Selected_Component then + return Safe_Prefixed_Reference (RO); + + -- In all other cases, designated object cannot be changed so + -- we are side effect free. + + else + return True; + end if; + end; + + -- Remove_Side_Effects generates an object renaming declaration to + -- capture the expression of a class-wide expression. In VM targets + -- the frontend performs no expansion for dispatching calls to + -- class- wide types since they are handled by the VM. Hence, we must + -- locate here if this node corresponds to a previous invocation of + -- Remove_Side_Effects to avoid a never ending loop in the frontend. + + elsif VM_Target /= No_VM + and then not Comes_From_Source (N) + and then Nkind (Parent (N)) = N_Object_Renaming_Declaration + and then Is_Class_Wide_Type (Etype (N)) + then + return True; + end if; + + -- For other than entity names and compile time known values, + -- check the node kind for special processing. + + case Nkind (N) is + + -- An attribute reference is side effect free if its expressions + -- are side effect free and its prefix is side effect free or + -- is an entity reference. + + -- Is this right? what about x'first where x is a variable??? + + when N_Attribute_Reference => + return Side_Effect_Free (Expressions (N), Name_Req, Variable_Ref) + and then Attribute_Name (N) /= Name_Input + and then (Is_Entity_Name (Prefix (N)) + or else Side_Effect_Free + (Prefix (N), Name_Req, Variable_Ref)); + + -- A binary operator is side effect free if and both operands are + -- side effect free. For this purpose binary operators include + -- membership tests and short circuit forms. + + when N_Binary_Op | N_Membership_Test | N_Short_Circuit => + return Side_Effect_Free (Left_Opnd (N), Name_Req, Variable_Ref) + and then + Side_Effect_Free (Right_Opnd (N), Name_Req, Variable_Ref); + + -- An explicit dereference is side effect free only if it is + -- a side effect free prefixed reference. + + when N_Explicit_Dereference => + return Safe_Prefixed_Reference (N); + + -- An expression with action is side effect free if its expression + -- is side effect free and it has no actions. + + when N_Expression_With_Actions => + return Is_Empty_List (Actions (N)) + and then + Side_Effect_Free (Expression (N), Name_Req, Variable_Ref); + + -- A call to _rep_to_pos is side effect free, since we generate + -- this pure function call ourselves. Moreover it is critically + -- important to make this exception, since otherwise we can have + -- discriminants in array components which don't look side effect + -- free in the case of an array whose index type is an enumeration + -- type with an enumeration rep clause. + + -- All other function calls are not side effect free + + when N_Function_Call => + return Nkind (Name (N)) = N_Identifier + and then Is_TSS (Name (N), TSS_Rep_To_Pos) + and then + Side_Effect_Free + (First (Parameter_Associations (N)), Name_Req, Variable_Ref); + + -- An indexed component is side effect free if it is a side + -- effect free prefixed reference and all the indexing + -- expressions are side effect free. + + when N_Indexed_Component => + return Side_Effect_Free (Expressions (N), Name_Req, Variable_Ref) + and then Safe_Prefixed_Reference (N); + + -- A type qualification is side effect free if the expression + -- is side effect free. + + when N_Qualified_Expression => + return Side_Effect_Free (Expression (N), Name_Req, Variable_Ref); + + -- A selected component is side effect free only if it is a side + -- effect free prefixed reference. If it designates a component + -- with a rep. clause it must be treated has having a potential + -- side effect, because it may be modified through a renaming, and + -- a subsequent use of the renaming as a macro will yield the + -- wrong value. This complex interaction between renaming and + -- removing side effects is a reminder that the latter has become + -- a headache to maintain, and that it should be removed in favor + -- of the gcc mechanism to capture values ??? + + when N_Selected_Component => + if Nkind (Parent (N)) = N_Explicit_Dereference + and then Has_Non_Standard_Rep (Designated_Type (Etype (N))) + then + return False; + else + return Safe_Prefixed_Reference (N); + end if; + + -- A range is side effect free if the bounds are side effect free + + when N_Range => + return Side_Effect_Free (Low_Bound (N), Name_Req, Variable_Ref) + and then + Side_Effect_Free (High_Bound (N), Name_Req, Variable_Ref); + + -- A slice is side effect free if it is a side effect free + -- prefixed reference and the bounds are side effect free. + + when N_Slice => + return Side_Effect_Free + (Discrete_Range (N), Name_Req, Variable_Ref) + and then Safe_Prefixed_Reference (N); + + -- A type conversion is side effect free if the expression to be + -- converted is side effect free. + + when N_Type_Conversion => + return Side_Effect_Free (Expression (N), Name_Req, Variable_Ref); + + -- A unary operator is side effect free if the operand + -- is side effect free. + + when N_Unary_Op => + return Side_Effect_Free (Right_Opnd (N), Name_Req, Variable_Ref); + + -- An unchecked type conversion is side effect free only if it + -- is safe and its argument is side effect free. + + when N_Unchecked_Type_Conversion => + return Safe_Unchecked_Type_Conversion (N) + and then + Side_Effect_Free (Expression (N), Name_Req, Variable_Ref); + + -- An unchecked expression is side effect free if its expression + -- is side effect free. + + when N_Unchecked_Expression => + return Side_Effect_Free (Expression (N), Name_Req, Variable_Ref); + + -- A literal is side effect free + + when N_Character_Literal | + N_Integer_Literal | + N_Real_Literal | + N_String_Literal => + return True; + + -- We consider that anything else has side effects. This is a bit + -- crude, but we are pretty close for most common cases, and we + -- are certainly correct (i.e. we never return True when the + -- answer should be False). + + when others => + return False; + end case; + end Side_Effect_Free; + + -- A list is side effect free if all elements of the list are side + -- effect free. + + function Side_Effect_Free + (L : List_Id; + Name_Req : Boolean := False; + Variable_Ref : Boolean := False) return Boolean + is + N : Node_Id; + + begin + if L = No_List or else L = Error_List then + return True; + + else + N := First (L); + while Present (N) loop + if not Side_Effect_Free (N, Name_Req, Variable_Ref) then + return False; + else + Next (N); + end if; + end loop; + + return True; + end if; + end Side_Effect_Free; + ---------------------------------- -- Silly_Boolean_Array_Not_Test -- ---------------------------------- diff --git a/gcc/ada/exp_util.ads b/gcc/ada/exp_util.ads index f14117c..40a6fbe 100644 --- a/gcc/ada/exp_util.ads +++ b/gcc/ada/exp_util.ads @@ -770,14 +770,14 @@ package Exp_Util is -- Given the node for a subexpression, this function replaces the node if -- necessary by an equivalent subexpression that is guaranteed to be side -- effect free. This is done by extracting any actions that could cause - -- side effects, and inserting them using Insert_Actions into the tree to - -- which Exp is attached. Exp must be analyzed and resolved before the call - -- and is analyzed and resolved on return. The Name_Req may only be set to + -- side effects, and inserting them using Insert_Actions into the tree + -- to which Exp is attached. Exp must be analyzed and resolved before the + -- call and is analyzed and resolved on return. Name_Req may only be set to -- True if Exp has the form of a name, and the effect is to guarantee that -- any replacement maintains the form of name. If Variable_Ref is set to -- TRUE, a variable is considered as side effect (used in implementing - -- Force_Evaluation). Note: after call to Remove_Side_Effects, it is safe - -- to call New_Copy_Tree to obtain a copy of the resulting expression. + -- Force_Evaluation). Note: after call to Remove_Side_Effects, it is + -- safe to call New_Copy_Tree to obtain a copy of the resulting expression. function Represented_As_Scalar (T : Entity_Id) return Boolean; -- Returns True iff the implementation of this type in code generation @@ -826,6 +826,29 @@ package Exp_Util is -- renamed subprogram. The node is rewritten to be an identifier that -- refers directly to the renamed subprogram, given by entity E. + function Side_Effect_Free + (N : Node_Id; + Name_Req : Boolean := False; + Variable_Ref : Boolean := False) return Boolean; + -- Determines if the tree N represents an expression that is known not + -- to have side effects. If this function returns True, then for example + -- a call to Remove_Side_Effects has no effect. + -- + -- Name_Req controls the handling of volatile variable references. If + -- Name_Req is False (the normal case), then volatile references are + -- considered to be side effects. If Name_Req is True, then volatility + -- of variables is ignored. + -- + -- If Variable_Ref is True, then all variable references are considered to + -- be side effects (regardless of volatility or the setting of Name_Req). + + function Side_Effect_Free + (L : List_Id; + Name_Req : Boolean := False; + Variable_Ref : Boolean := False) return Boolean; + -- Determines if all elements of the list L are side effect free. Name_Req + -- and Variable_Ref are as described above. + procedure Silly_Boolean_Array_Not_Test (N : Node_Id; T : Entity_Id); -- N is the node for a boolean array NOT operation, and T is the type of -- the array. This routine deals with the silly case where the subtype of diff --git a/gcc/ada/par-ch13.adb b/gcc/ada/par-ch13.adb index 4c661a5..fffa594 100644 --- a/gcc/ada/par-ch13.adb +++ b/gcc/ada/par-ch13.adb @@ -149,9 +149,9 @@ package body Ch13 is function Get_Aspect_Specifications (Semicolon : Boolean := True) return List_Id is - Aspects : List_Id; - Aspect : Node_Id; A_Id : Aspect_Id; + Aspect : Node_Id; + Aspects : List_Id; OK : Boolean; begin @@ -173,9 +173,13 @@ package body Ch13 is loop OK := True; + -- The aspect mark is not an identifier + if Token /= Tok_Identifier then Error_Msg_SC ("aspect identifier expected"); + -- Skip the whole aspect specification list + if Semicolon then Resync_Past_Semicolon; end if; @@ -183,17 +187,16 @@ package body Ch13 is return Aspects; end if; - -- We have an identifier (which should be an aspect identifier) - A_Id := Get_Aspect_Id (Token_Name); Aspect := Make_Aspect_Specification (Token_Ptr, Identifier => Token_Node); - -- No valid aspect identifier present + -- The aspect mark is not recognized if A_Id = No_Aspect then Error_Msg_SC ("aspect identifier expected"); + OK := False; -- Check bad spelling @@ -209,17 +212,23 @@ package body Ch13 is Scan; -- past incorrect identifier if Token = Tok_Apostrophe then - Scan; -- past ' + Scan; -- past apostrophe Scan; -- past presumably CLASS end if; + -- Attempt to parse the aspect definition by assuming it is an + -- expression. + if Token = Tok_Arrow then - Scan; -- Past arrow + Scan; -- past arrow Set_Expression (Aspect, P_Expression); - OK := False; + + -- The aspect may behave as a boolean aspect elsif Token = Tok_Comma then - OK := False; + null; + + -- Otherwise the aspect contains a junk definition else if Semicolon then @@ -229,7 +238,7 @@ package body Ch13 is return Aspects; end if; - -- OK aspect scanned + -- Aspect mark is OK else Scan; -- past identifier @@ -237,60 +246,58 @@ package body Ch13 is -- Check for 'Class present if Token = Tok_Apostrophe then - if not Class_Aspect_OK (A_Id) then - Error_Msg_Node_1 := Identifier (Aspect); - Error_Msg_SC ("aspect& does not permit attribute here"); - Scan; -- past apostrophe - Scan; -- past presumed CLASS - OK := False; - - else + if Class_Aspect_OK (A_Id) then Scan; -- past apostrophe - if Token /= Tok_Identifier - or else Token_Name /= Name_Class + if Token = Tok_Identifier + and then Token_Name = Name_Class then + Scan; -- past CLASS + Set_Class_Present (Aspect); + else Error_Msg_SC ("Class attribute expected here"); OK := False; if Token = Tok_Identifier then Scan; -- past identifier not CLASS end if; - - else - Scan; -- past CLASS - Set_Class_Present (Aspect); end if; + + -- The aspect does not allow 'Class + + else + Error_Msg_Node_1 := Identifier (Aspect); + Error_Msg_SC ("aspect& does not permit attribute here"); + OK := False; + + Scan; -- past apostrophe + Scan; -- past presumably CLASS end if; end if; - -- Test case of missing aspect definition + -- Check for a missing aspect definition. Aspects with optional + -- definitions are not considered. - if Token = Tok_Comma - or else Token = Tok_Semicolon - then + if Token = Tok_Comma or else Token = Tok_Semicolon then if Aspect_Argument (A_Id) /= Optional_Expression - and then - Aspect_Argument (A_Id) /= Optional_Name + and then Aspect_Argument (A_Id) /= Optional_Name then Error_Msg_Node_1 := Identifier (Aspect); Error_Msg_AP ("aspect& requires an aspect definition"); OK := False; end if; + -- Check for a missing arrow when the aspect has a definition + elsif not Semicolon and then Token /= Tok_Arrow then if Aspect_Argument (A_Id) /= Optional_Expression - and then - Aspect_Argument (A_Id) /= Optional_Name + and then Aspect_Argument (A_Id) /= Optional_Name then - -- The name or expression may be there, but the arrow is - -- missing. Skip to the end of the declaration. - T_Arrow; Resync_To_Semicolon; end if; - -- Here we have an aspect definition + -- Otherwise we have an aspect definition else if Token = Tok_Arrow then @@ -300,9 +307,107 @@ package body Ch13 is OK := False; end if; + -- Detect a common error where the non-null definition of + -- aspect Depends, Global, Refined_Depends or Refined_Global + -- must be enclosed in parentheses. + + if Token /= Tok_Left_Paren and then Token /= Tok_Null then + + -- [Refined_]Depends + + if A_Id = Aspect_Depends + or else + A_Id = Aspect_Refined_Depends + then + Error_Msg_SC -- CODEFIX + ("missing ""("""); + Resync_Past_Malformed_Aspect; + + -- Return when the current aspect is the last in the list + -- of specifications and the list applies to a body. + + if Token = Tok_Is then + return Aspects; + end if; + + -- [Refined_]Global + + elsif A_Id = Aspect_Global + or else + A_Id = Aspect_Refined_Global + then + declare + Scan_State : Saved_Scan_State; + + begin + Save_Scan_State (Scan_State); + Scan; -- past item or mode_selector + + -- Emit an error when the aspect has a mode_selector + -- as the moded_global_list must be parenthesized: + -- with Global => Output => Item + + if Token = Tok_Arrow then + Restore_Scan_State (Scan_State); + Error_Msg_SC -- CODEFIX + ("missing ""("""); + Resync_Past_Malformed_Aspect; + + -- Return when the current aspect is the last in + -- the list of specifications and the list applies + -- to a body. + + if Token = Tok_Is then + return Aspects; + end if; + + elsif Token = Tok_Comma then + Scan; -- past comma + + -- An item followed by a comma does not need to + -- be parenthesized if the next token is a valid + -- aspect name: + -- with Global => Item, + -- Aspect => ... + + if Token = Tok_Identifier + and then Get_Aspect_Id (Token_Name) /= No_Aspect + then + Restore_Scan_State (Scan_State); + + -- Otherwise this is a list of items in which case + -- the list must be parenthesized. + + else + Restore_Scan_State (Scan_State); + Error_Msg_SC -- CODEFIX + ("missing ""("""); + Resync_Past_Malformed_Aspect; + + -- Return when the current aspect is the last + -- in the list of specifications and the list + -- applies to a body. + + if Token = Tok_Is then + return Aspects; + end if; + end if; + + -- The definition of [Refined_]Global does not need to + -- be parenthesized. + + else + Restore_Scan_State (Scan_State); + end if; + end; + end if; + end if; + + -- Parse the aspect definition depening on the expected + -- argument kind. + if Aspect_Argument (A_Id) = Name - or else - Aspect_Argument (A_Id) = Optional_Name + or else Aspect_Argument (A_Id) = Optional_Name then Set_Expression (Aspect, P_Name); @@ -315,18 +420,21 @@ package body Ch13 is end if; end if; - -- If OK clause scanned, add it to the list + -- Add the aspect to the resulting list only when it was properly + -- parsed. if OK then Append (Aspect, Aspects); end if; + -- The aspect specification list contains more than one aspect + if Token = Tok_Comma then Scan; -- past comma goto Continue; - -- Recognize the case where a comma is missing between two - -- aspects, issue an error and proceed with next aspect. + -- Check for a missing comma between two aspects. Emit an error + -- and proceed to the next aspect. elsif Token = Tok_Identifier and then Get_Aspect_Id (Token_Name) /= No_Aspect @@ -338,20 +446,25 @@ package body Ch13 is Save_Scan_State (Scan_State); Scan; -- past identifier - if Token = Tok_Arrow then + -- Attempt to detect ' or => following a potential aspect + -- mark. + + if Token = Tok_Apostrophe or else Token = Tok_Arrow then Restore_Scan_State (Scan_State); Error_Msg_AP -- CODEFIX ("|missing "","""); goto Continue; + -- The construct following the current aspect is not an + -- aspect. + else Restore_Scan_State (Scan_State); end if; end; - -- Recognize the case where a semicolon was mistyped for a comma - -- between two aspects, issue an error and proceed with next - -- aspect. + -- Check for a mistyped semicolon in place of a comma between two + -- aspects. Emit an error and proceed to the next aspect. elsif Token = Tok_Semicolon then declare @@ -366,20 +479,22 @@ package body Ch13 is then Scan; -- past identifier - if Token = Tok_Arrow then + -- Attempt to detect ' or => following a potential aspect + -- mark. + + if Token = Tok_Apostrophe or else Token = Tok_Arrow then Restore_Scan_State (Scan_State); Error_Msg_SC -- CODEFIX ("|"";"" should be "","""); Scan; -- past semicolon goto Continue; - - else - Restore_Scan_State (Scan_State); end if; - - else - Restore_Scan_State (Scan_State); end if; + + -- The construct following the current aspect is not an + -- aspect. + + Restore_Scan_State (Scan_State); end; end if; @@ -397,7 +512,6 @@ package body Ch13 is end loop; return Aspects; - end Get_Aspect_Specifications; -------------------------------------------- diff --git a/gcc/ada/par-sync.adb b/gcc/ada/par-sync.adb index 0cf73db..83987da 100644 --- a/gcc/ada/par-sync.adb +++ b/gcc/ada/par-sync.adb @@ -148,47 +148,75 @@ package body Sync is end if; end Resync_Init; - --------------------------- - -- Resync_Past_Semicolon -- - --------------------------- + ---------------------------------- + -- Resync_Past_Malformed_Aspect -- + ---------------------------------- - procedure Resync_Past_Semicolon is + procedure Resync_Past_Malformed_Aspect is begin Resync_Init; loop - -- Done if we are at a semicolon + -- A comma may separate two aspect specifications, but it may also + -- delimit multiple arguments of a single aspect. - if Token = Tok_Semicolon then - Scan; -- past semicolon + if Token = Tok_Comma then + declare + Scan_State : Saved_Scan_State; + + begin + Save_Scan_State (Scan_State); + Scan; -- past comma + + -- The identifier following the comma is a valid aspect, the + -- current malformed aspect has been successfully skipped. + + if Token = Tok_Identifier + and then Get_Aspect_Id (Token_Name) /= No_Aspect + then + Restore_Scan_State (Scan_State); + exit; + + -- The comma is delimiting multiple arguments of an aspect + + else + Restore_Scan_State (Scan_State); + end if; + end; + + -- An IS signals the last aspect specification when the related + -- context is a body. + + elsif Token = Tok_Is then exit; - -- Done if we are at a token which normally appears only after - -- a semicolon. One special glitch is that the keyword private is - -- in this category only if it does NOT appear after WITH. + -- A semicolon signals the last aspect specification - elsif Token in Token_Class_After_SM - and then (Token /= Tok_Private or else Prev_Token /= Tok_With) - then + elsif Token = Tok_Semicolon then exit; - -- Otherwise keep going + -- In the case of a mistyped semicolon, any token which follows a + -- semicolon signals the last aspect specification. - else - Scan; + elsif Token in Token_Class_After_SM then + exit; end if; + + -- Keep on resyncing + + Scan; end loop; -- Fall out of loop with resynchronization complete Resync_Resume; - end Resync_Past_Semicolon; + end Resync_Past_Malformed_Aspect; - ------------------------- - -- Resync_To_Semicolon -- - ------------------------- + --------------------------- + -- Resync_Past_Semicolon -- + --------------------------- - procedure Resync_To_Semicolon is + procedure Resync_Past_Semicolon is begin Resync_Init; @@ -196,6 +224,7 @@ package body Sync is -- Done if we are at a semicolon if Token = Tok_Semicolon then + Scan; -- past semicolon exit; -- Done if we are at a token which normally appears only after @@ -217,7 +246,7 @@ package body Sync is -- Fall out of loop with resynchronization complete Resync_Resume; - end Resync_To_Semicolon; + end Resync_Past_Semicolon; ---------------------------------------------- -- Resync_Past_Semicolon_Or_To_Loop_Or_Then -- @@ -275,35 +304,6 @@ package body Sync is end if; end Resync_Resume; - -------------------- - -- Resync_To_When -- - -------------------- - - procedure Resync_To_When is - begin - Resync_Init; - - loop - -- Done if at semicolon, WHEN or IS - - if Token = Tok_Semicolon - or else Token = Tok_When - or else Token = Tok_Is - then - exit; - - -- Otherwise keep going - - else - Scan; - end if; - end loop; - - -- Fall out of loop with resynchronization complete - - Resync_Resume; - end Resync_To_When; - --------------------------- -- Resync_Semicolon_List -- --------------------------- @@ -340,4 +340,68 @@ package body Sync is Resync_Resume; end Resync_Semicolon_List; + ------------------------- + -- Resync_To_Semicolon -- + ------------------------- + + procedure Resync_To_Semicolon is + begin + Resync_Init; + + loop + -- Done if we are at a semicolon + + if Token = Tok_Semicolon then + exit; + + -- Done if we are at a token which normally appears only after + -- a semicolon. One special glitch is that the keyword private is + -- in this category only if it does NOT appear after WITH. + + elsif Token in Token_Class_After_SM + and then (Token /= Tok_Private or else Prev_Token /= Tok_With) + then + exit; + + -- Otherwise keep going + + else + Scan; + end if; + end loop; + + -- Fall out of loop with resynchronization complete + + Resync_Resume; + end Resync_To_Semicolon; + + -------------------- + -- Resync_To_When -- + -------------------- + + procedure Resync_To_When is + begin + Resync_Init; + + loop + -- Done if at semicolon, WHEN or IS + + if Token = Tok_Semicolon + or else Token = Tok_When + or else Token = Tok_Is + then + exit; + + -- Otherwise keep going + + else + Scan; + end if; + end loop; + + -- Fall out of loop with resynchronization complete + + Resync_Resume; + end Resync_To_When; + end Sync; diff --git a/gcc/ada/par.adb b/gcc/ada/par.adb index 93f5bb5..7de8458 100644 --- a/gcc/ada/par.adb +++ b/gcc/ada/par.adb @@ -1079,6 +1079,10 @@ function Par (Configuration_Pragmas : Boolean) return List_Id is -- advanced to the next vertical bar, arrow, or semicolon, whichever -- comes first. We also quit if we encounter an end of file. + procedure Resync_Cunit; + -- Synchronize to next token which could be the start of a compilation + -- unit, or to the end of file token. + procedure Resync_Expression; -- Used if an error is detected during the parsing of an expression. -- It skips past tokens until either a token which cannot be part of @@ -1087,6 +1091,11 @@ function Par (Configuration_Pragmas : Boolean) return List_Id is -- current parenthesis level (a parenthesis level counter is maintained -- to carry out this test). + procedure Resync_Past_Malformed_Aspect; + -- Used when parsing aspect specifications to skip a malformed aspect. + -- The scan pointer is positioned next to a comma, a semicolon or "is" + -- when the aspect applies to a body. + procedure Resync_Past_Semicolon; -- Used if an error occurs while scanning a sequence of declarations. -- The scan pointer is positioned past the next semicolon and the scan @@ -1094,30 +1103,26 @@ function Par (Configuration_Pragmas : Boolean) return List_Id is -- starts a declaration (but we make sure to skip at least one token -- in this case, to avoid getting stuck in a loop). - procedure Resync_To_Semicolon; - -- Similar to Resync_Past_Semicolon, except that the scan pointer is - -- left pointing to the semicolon rather than past it. - procedure Resync_Past_Semicolon_Or_To_Loop_Or_Then; -- Used if an error occurs while scanning a sequence of statements. The -- scan pointer is positioned past the next semicolon, or to the next -- occurrence of either then or loop, and the scan resumes. - procedure Resync_To_When; - -- Used when an error occurs scanning an entry index specification. The - -- scan pointer is positioned to the next WHEN (or to IS or semicolon if - -- either of these appear before WHEN, indicating another error has - -- occurred). - procedure Resync_Semicolon_List; -- Used if an error occurs while scanning a parenthesized list of items -- separated by semicolons. The scan pointer is advanced to the next -- semicolon or right parenthesis at the outer parenthesis level, or -- to the next is or RETURN keyword occurrence, whichever comes first. - procedure Resync_Cunit; - -- Synchronize to next token which could be the start of a compilation - -- unit, or to the end of file token. + procedure Resync_To_Semicolon; + -- Similar to Resync_Past_Semicolon, except that the scan pointer is + -- left pointing to the semicolon rather than past it. + + procedure Resync_To_When; + -- Used when an error occurs scanning an entry index specification. The + -- scan pointer is positioned to the next WHEN (or to IS or semicolon if + -- either of these appear before WHEN, indicating another error has + -- occurred). end Sync; -------------- diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads index cb8b0ee..af476c0 100644 --- a/gcc/ada/sinfo.ads +++ b/gcc/ada/sinfo.ads @@ -649,9 +649,8 @@ package Sinfo is -- Mod for signed integer types is expanded into equivalent expressions -- using Rem (which is % in C) and other C-available operators. - -- The Actions list of an Expression_With_Actions node has any object - -- declarations removed, so that it is composed only of expressions - -- (so that DO X,... Y IN Z can be represented as (X, .. Y, Z) in C). + -- The Actions list of an Expression_With_Actions node does not contain + -- any declarations,(so that DO X, .. Y IN Z becomes (X, .. Y, Z) in C). ------------------------------------ -- Description of Semantic Fields -- @@ -7426,11 +7425,8 @@ package Sinfo is -- not a proper expression), and in the long term all cases of this -- idiom should instead use a new node kind N_Compound_Statement. - -- Note: In Modify_Tree_For_C, we eliminate declarations from the list - -- of actions, inserting them at the outer level. If we move an object - -- declaration with an initialization expression in this manner, then - -- the action is replaced by an appropriate assignment, otherwise it is - -- removed from the list of actions. + -- Note: In Modify_Tree_For_C, we never generate any declarations in + -- the action list, which can contain only non-declarative statements. -------------------- -- Free Statement -- |