https://gcc.gnu.org/g:4de3be28bab44350548cb559b61f69cc040b4016
commit r16-2413-g4de3be28bab44350548cb559b61f69cc040b4016 Author: Javier Miranda <mira...@adacore.com> Date: Mon May 12 18:46:11 2025 +0000 ada: Wrong dispatch on result in presence of dependent expression The compiler generates wrong code in a dispatching call on result when the call is performed under dependent conditional expressions or case-expressions. gcc/ada/ChangeLog: * sinfo.ads (Is_Expanded_Dispatching_Call): New flag. (Tag_Propagated): New flag. * exp_ch6.adb (Expand_Call_Helper): Propagate the tag when the dispatching call is placed in conditionl expressions or case-expressions. * sem_ch5.adb (Analyze_Assignment): For assignment of tag- indeterminate expression, do not propagate the tag if previously done. * sem_disp.adb (Is_Tag_Indeterminate): Add missing support for conditional expression and case expression. * exp_disp.ads (Is_Expanded_Dispatching_Call): Removed. Function replaced by a new flag in the nodes. * exp_disp.adb (Expand_Dispatching_Call): Set a flag in the call node to remember that the call has been expanded. (Is_Expanded_Dispatching_Call): Function removed. * gen_il-fields.ads (Tag_Propagated): New flag. (Is_Expanded_Dispatching_Call): New flag. * gen_il-gen-gen_nodes.adb (Tag_Propagated): New flag. (Is_Expanded_Dispatching_Call): New flag. Diff: --- gcc/ada/exp_ch6.adb | 49 ++++++++++++++++++++++++++++------------ gcc/ada/exp_disp.adb | 15 +++--------- gcc/ada/exp_disp.ads | 3 --- gcc/ada/gen_il-fields.ads | 2 ++ gcc/ada/gen_il-gen-gen_nodes.adb | 9 ++++++-- gcc/ada/sem_ch5.adb | 9 +++++++- gcc/ada/sem_disp.adb | 47 ++++++++++++++++++++++++++++++++++++++ gcc/ada/sinfo.ads | 36 +++++++++++++++++++++-------- 8 files changed, 127 insertions(+), 43 deletions(-) diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb index 81686abbad81..1195582aaeab 100644 --- a/gcc/ada/exp_ch6.adb +++ b/gcc/ada/exp_ch6.adb @@ -4756,27 +4756,34 @@ package body Exp_Ch6 is then declare Ass : Node_Id := Empty; + Par : Node_Id := Parent (Call_Node); begin - if Nkind (Parent (Call_Node)) = N_Assignment_Statement then - Ass := Parent (Call_Node); + -- Search for the LHS of an enclosing assignment statement to a + -- classwide type object (if present) and propagate the tag to + -- this function call. + + while Nkind (Par) in N_Case_Expression + | N_Case_Expression_Alternative + | N_Explicit_Dereference + | N_If_Expression + | N_Qualified_Expression + | N_Unchecked_Type_Conversion + loop + if Nkind (Par) = N_Case_Expression_Alternative then + Par := Parent (Par); + end if; - elsif Nkind (Parent (Call_Node)) = N_Qualified_Expression - and then Nkind (Parent (Parent (Call_Node))) = - N_Assignment_Statement - then - Ass := Parent (Parent (Call_Node)); + exit when not Is_Tag_Indeterminate (Par); - elsif Nkind (Parent (Call_Node)) = N_Explicit_Dereference - and then Nkind (Parent (Parent (Call_Node))) = - N_Assignment_Statement - then - Ass := Parent (Parent (Call_Node)); - end if; + Par := Parent (Par); + end loop; - if Present (Ass) - and then Is_Class_Wide_Type (Etype (Name (Ass))) + if Nkind (Par) = N_Assignment_Statement + and then Is_Class_Wide_Type (Etype (Name (Par))) then + Ass := Par; + -- Move the error messages below to sem??? if Is_Access_Type (Etype (Call_Node)) then @@ -4789,6 +4796,12 @@ package body Exp_Ch6 is Call_Node, Root_Type (Etype (Name (Ass)))); else Propagate_Tag (Name (Ass), Call_Node); + + -- Remember that the tag has been propagated to avoid + -- propagating it again, as part of the (bottom-up) + -- analysis of the enclosing assignment. + + Set_Tag_Propagated (Name (Ass)); end if; elsif Etype (Call_Node) /= Root_Type (Etype (Name (Ass))) then @@ -4799,6 +4812,12 @@ package body Exp_Ch6 is else Propagate_Tag (Name (Ass), Call_Node); + + -- Remember that the tag has been propagated to avoid + -- propagating it again, as part of the (bottom-up) + -- analysis of the enclosing assignment. + + Set_Tag_Propagated (Name (Ass)); end if; -- The call will be rewritten as a dispatching call, and diff --git a/gcc/ada/exp_disp.adb b/gcc/ada/exp_disp.adb index 6cd4f6a515c2..619ac407cb0a 100644 --- a/gcc/ada/exp_disp.adb +++ b/gcc/ada/exp_disp.adb @@ -801,7 +801,7 @@ package body Exp_Disp is -- No action needed if the dispatching call has been already expanded - or else Is_Expanded_Dispatching_Call (Name (Call_Node)) + or else Is_Expanded_Dispatching_Call (Call_Node) then return; end if; @@ -1209,6 +1209,8 @@ package body Exp_Disp is -- the generation of spurious warnings under ZFP run-time. Analyze_And_Resolve (Call_Node, Call_Typ, Suppress => All_Checks); + + Set_Is_Expanded_Dispatching_Call (Call_Node); end Expand_Dispatching_Call; --------------------------------- @@ -2350,17 +2352,6 @@ package body Exp_Disp is and then not Restriction_Active (No_Dispatching_Calls); end Has_DT; - ---------------------------------- - -- Is_Expanded_Dispatching_Call -- - ---------------------------------- - - function Is_Expanded_Dispatching_Call (N : Node_Id) return Boolean is - begin - return Nkind (N) in N_Subprogram_Call - and then Nkind (Name (N)) = N_Explicit_Dereference - and then Is_Dispatch_Table_Entity (Etype (Name (N))); - end Is_Expanded_Dispatching_Call; - ------------------------------------- -- Is_Predefined_Dispatching_Alias -- ------------------------------------- diff --git a/gcc/ada/exp_disp.ads b/gcc/ada/exp_disp.ads index 3cba8ca447e3..76f592358005 100644 --- a/gcc/ada/exp_disp.ads +++ b/gcc/ada/exp_disp.ads @@ -236,9 +236,6 @@ package Exp_Disp is function Has_CPP_Constructors (Typ : Entity_Id) return Boolean; -- Returns true if the type has CPP constructors - function Is_Expanded_Dispatching_Call (N : Node_Id) return Boolean; - -- Returns true if N is the expanded code of a dispatching call - function Make_DT (Typ : Entity_Id) return List_Id; -- Expand the declarations for the Dispatch Table of Typ diff --git a/gcc/ada/gen_il-fields.ads b/gcc/ada/gen_il-fields.ads index 68adcf4a71a6..18edec26742c 100644 --- a/gcc/ada/gen_il-fields.ads +++ b/gcc/ada/gen_il-fields.ads @@ -255,6 +255,7 @@ package Gen_IL.Fields is Is_Entry_Barrier_Function, Is_Expanded_Build_In_Place_Call, Is_Expanded_Constructor_Call, + Is_Expanded_Dispatching_Call, Is_Expanded_Prefixed_Call, Is_Folded_In_Parser, Is_Generic_Contract_Pragma, @@ -400,6 +401,7 @@ package Gen_IL.Fields is Suppress_Loop_Warnings, Synchronized_Present, Tagged_Present, + Tag_Propagated, Target, Call_Or_Target_Loop, Target_Type, diff --git a/gcc/ada/gen_il-gen-gen_nodes.adb b/gcc/ada/gen_il-gen-gen_nodes.adb index f4e79173502c..412565f42a8b 100644 --- a/gcc/ada/gen_il-gen-gen_nodes.adb +++ b/gcc/ada/gen_il-gen-gen_nodes.adb @@ -149,6 +149,7 @@ begin -- Gen_IL.Gen.Gen_Nodes Sm (Is_Controlling_Actual, Flag), Sm (Is_Overloaded, Flag), Sm (Is_Static_Expression, Flag), + Sm (Is_Expanded_Dispatching_Call, Flag), Sm (Must_Not_Freeze, Flag), Sm (Raises_Constraint_Error, Flag))); @@ -181,7 +182,8 @@ begin -- Gen_IL.Gen.Gen_Nodes Sm (Is_Elaboration_Warnings_OK_Node, Flag), Sm (Is_SPARK_Mode_On_Node, Flag), Sm (Original_Discriminant, Node_Id), - Sm (Redundant_Use, Flag))); + Sm (Redundant_Use, Flag), + Sm (Tag_Propagated, Flag))); Cc (N_Operator_Symbol, N_Direct_Name, (Sy (Strval, String_Id))); @@ -346,7 +348,8 @@ begin -- Gen_IL.Gen.Gen_Nodes (Sy (Prefix, Node_Id), Sm (Actual_Designated_Subtype, Node_Id), Sm (Atomic_Sync_Required, Flag), - Sm (Has_Dereference_Action, Flag))); + Sm (Has_Dereference_Action, Flag), + Sm (Tag_Propagated, Flag))); Cc (N_Expression_With_Actions, N_Subexpr, (Sy (Actions, List_Id, Default_No_List), @@ -463,6 +466,7 @@ begin -- Gen_IL.Gen.Gen_Nodes Sm (Do_Length_Check, Flag), Sm (Do_Overflow_Check, Flag), Sm (Float_Truncate, Flag), + Sm (Tag_Propagated, Flag), Sm (Rounded_Result, Flag))); Cc (N_Unchecked_Type_Conversion, N_Subexpr, @@ -905,6 +909,7 @@ begin -- Gen_IL.Gen.Gen_Nodes Sm (Cleanup_Actions, List_Id), Sm (Exception_Junk, Flag), Sm (Is_Abort_Block, Flag), + Sm (Is_Expanded_Dispatching_Call, Flag), Sm (Is_Initialization_Block, Flag), Sm (Is_Task_Master, Flag))); diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb index e1d6be424ed4..0661e64d095d 100644 --- a/gcc/ada/sem_ch5.adb +++ b/gcc/ada/sem_ch5.adb @@ -807,7 +807,14 @@ package body Sem_Ch5 is if Is_Tag_Indeterminate (Rhs) then if Is_Class_Wide_Type (T1) then - Propagate_Tag (Lhs, Rhs); + + -- No need to propagate the tag when the RHS has function calls + -- that already propagated it (see Expand_Call_Helper), or if + -- some error was reported analyzing RHS. + + if not (Error_Posted (Rhs) or else Tag_Propagated (Lhs)) then + Propagate_Tag (Lhs, Rhs); + end if; elsif Nkind (Rhs) = N_Function_Call and then Is_Entity_Name (Name (Rhs)) diff --git a/gcc/ada/sem_disp.adb b/gcc/ada/sem_disp.adb index b70c7b4fea44..5a8bd58b8b81 100644 --- a/gcc/ada/sem_disp.adb +++ b/gcc/ada/sem_disp.adb @@ -3085,6 +3085,52 @@ package body Sem_Disp is then return Is_Tag_Indeterminate (Prefix (Orig_Node)); + -- An if-expression is tag-indeterminate if all of the dependent + -- expressions are tag-indeterminate (RM 4.5.7 (17/3)). + + elsif Nkind (Orig_Node) = N_If_Expression then + declare + Cond : constant Node_Id := First (Expressions (Orig_Node)); + Expr : Node_Id := Next (Cond); + + begin + if not Is_Tag_Indeterminate (Original_Node (Expr)) then + return False; + end if; + + Next (Expr); + + if Present (Expr) + and then not Is_Tag_Indeterminate (Original_Node (Expr)) + then + return False; + end if; + + return True; + end; + + -- A case-expression is tag-indeterminate if all of the dependent + -- expressions are tag-indeterminate (RM 4.5.7 (17/3)). + + elsif Nkind (Orig_Node) = N_Case_Expression then + declare + Alt : Node_Id := First (Alternatives (Orig_Node)); + Expr : Node_Id; + + begin + while Present (Alt) loop + Expr := Expression (Alt); + + if not Is_Tag_Indeterminate (Original_Node (Expr)) then + return False; + end if; + + Next (Alt); + end loop; + + return True; + end; + else return False; end if; @@ -3245,6 +3291,7 @@ package body Sem_Disp is elsif Nkind (Actual) = N_Explicit_Dereference and then Nkind (Original_Node (Prefix (Actual))) = N_Function_Call then + pragma Assert (Is_Expanded_Dispatching_Call (Actual)); return; -- When expansion is suppressed, an unexpanded call to 'Input can occur, diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads index c63a97dbcc63..3d11d5c5aa67 100644 --- a/gcc/ada/sinfo.ads +++ b/gcc/ada/sinfo.ads @@ -402,16 +402,17 @@ package Sinfo is -- Has_Secondary_Private_View set in generic units -- "plus fields for expression" - -- Paren_Count number of parentheses levels - -- Etype type of the expression - -- Is_Overloaded >1 type interpretation exists - -- Is_Static_Expression set for static expression - -- Raises_Constraint_Error evaluation raises CE - -- Must_Not_Freeze set if must not freeze - -- Do_Range_Check set if a range check needed - -- Has_Dynamic_Length_Check set if length check inserted - -- Assignment_OK set if modification is OK - -- Is_Controlling_Actual set for controlling argument + -- Paren_Count number of parentheses levels + -- Etype type of the expression + -- Is_Overloaded >1 type interpretation exists + -- Is_Static_Expression set for static expression + -- Raises_Constraint_Error evaluation raises CE + -- Must_Not_Freeze set if must not freeze + -- Do_Range_Check set if a range check needed + -- Has_Dynamic_Length_Check set if length check inserted + -- Assignment_OK set if modification is OK + -- Is_Controlling_Actual set for controlling argument + -- Is_Expanded_Dispatching_Call set for expanded dispatching calls -- Note: see under (EXPRESSION) for further details on the use of -- the Paren_Count field to record the number of parentheses levels. @@ -1664,6 +1665,10 @@ package Sinfo is -- actuals to support a build-in-place style of call have been added to -- the call. + -- Is_Expanded_Dispatching_Call + -- This flag is set in N_Block_Statement, and expression nodes to + -- indicate that it is an expanded dispatching call. + -- Is_Expanded_Prefixed_Call -- This flag is set in N_Function_Call and N_Procedure_Call_Statement -- nodes to indicate that it is an expanded prefixed call. @@ -2321,6 +2326,13 @@ package Sinfo is -- statement applies to. Finally, if Analyze_Continue_Statement detects -- an error, this field is set to Empty. + -- Tag_Propagated + -- This flag is set in N_Identifier, N_Explicit_Dereference, and N_Type_ + -- Conversion nodes that are the LHS of an assignment statement. Used to + -- remember that the RHS of the assignment has tag indeterminate function + -- calls and the tag has been propagated to the calls (as part of the + -- bottom-up analysis of the RHS of the assignment statement). + -- Target_Type -- Used in an N_Validate_Unchecked_Conversion node to point to the target -- type entity for the unchecked conversion instantiation which gigi must @@ -2507,6 +2519,7 @@ package Sinfo is -- Has_Private_View (set in generic units) -- Has_Secondary_Private_View (set in generic units) -- Redundant_Use + -- Tag_Propagated -- Atomic_Sync_Required -- plus fields for expression @@ -3820,6 +3833,7 @@ package Sinfo is -- Prefix -- Actual_Designated_Subtype -- Has_Dereference_Action + -- Tag_Propagated -- Atomic_Sync_Required -- plus fields for expression @@ -4755,6 +4769,7 @@ package Sinfo is -- Conversion_OK -- Do_Overflow_Check -- Rounded_Result + -- Tag_Propagated -- plus fields for expression -- Note: if a range check is required, then the Do_Range_Check flag @@ -5196,6 +5211,7 @@ package Sinfo is -- Has_Created_Identifier -- Is_Abort_Block -- Is_Asynchronous_Call_Block + -- Is_Expanded_Dispatching_Call -- Is_Initialization_Block -- Is_Task_Allocation_Block -- Is_Task_Master