From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com [IPv6:2a00:1450:4864:20::32e]) by sourceware.org (Postfix) with ESMTPS id 6E5603858416 for ; Mon, 20 May 2024 07:49:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6E5603858416 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=adacore.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=adacore.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6E5603858416 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::32e ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1716191368; cv=none; b=gDKSIXQGFFfZYlyd/bfY/qL0W3qgYEhWn3A8Zq9FBdZQCfcvWflFTo0lAVPhwXaN8oUGL1X2j2KRGwJyBB9fT13biyJL8sm2Jyj8dpWaP5NCnx5CjIE3cIoIhDSk+9kHFgdGRVbgqZzCnQduWSa9JwTpCXkzHLvVCzgWXQee5dQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1716191368; c=relaxed/simple; bh=YXMEBbROXmu5NKRAeKIaeQuWAO4KtzrQvTWYNzWXMR0=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=MVsEsMzlyPVz8LCgIbBwLo8S5hOBJuhUFjg1XywjYKuQDyCdME96PNYjdPgkWQcDCAJrRTWQa5L0TsrW5k8M8C5XDnuGwVmESXhRwBszY5wQX50VXDtEZaulTuuQxNb+muAXDKTCFPfCg8xTbILGNdgi4h4ur8ID4xPLtFdv2aY= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-wm1-x32e.google.com with SMTP id 5b1f17b1804b1-41fd5dc0480so17084225e9.1 for ; Mon, 20 May 2024 00:49:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1716191361; x=1716796161; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=UI9wsDXywhRArb+JK0hAlY5uI8NBA3ax56Mc9s603OA=; b=GoSas9de1ZnqdMOQpN5zew/GHiKlkNUAkEBx54RFmttJjbw5HjOuWenqsZSVcPNOFX HSUKR3TINk4ivlrGIXyrZeB81cW5Kghq/mZUZz/T2FjnzkQNLZiMPPJz/+w4gzFatrS4 elROwTzHdYRiQZ+jaeoCgqG5HiPNcDDaWYpo1f/HEfp2orRrQKt/ZUjSnYb5ZZhF3RJX S04ryN5EjiKAgcpx8ar6KN+eOLKGQFobZ69S4SDSABpJW7jR4ChanGjt4fn+4P/E0fSq +ZrevRNiGI7FrQ9q/ve5ydG9vDCkbdb2XYXIz9fdjUnn49HPojfEskYp1PmWicjgV9ji s+dA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716191361; x=1716796161; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UI9wsDXywhRArb+JK0hAlY5uI8NBA3ax56Mc9s603OA=; b=ZZFazWTTbMtkKSj3TXPacAN2WC2Iq7LZIR7ycA3lKwmisnwGoejD53Eq/pFvHLNaRl lZs/+kqeuqK/z6YYp/Luh5xOykICr/PDlIsvSNXWRR9ZOz8lmw1aSoaFTn3WD9Eg5L9j kBBFdQhAgk9OqEfrQpJSqEtNBBj4Nva4cl4R71Czr2PiuJjKssMOP9Bm+l+H5FhhHn5D iAjoSd/YnQ4Pn7DF/wAA+tK2BltPWJ41j2WKRMOOjL4AAPhEQVUByTZlwjI8TNT8YQYp JpIeW477eCITs11gNplVf/EZGikSxHgcKndTtcucpScDeoU2jSsEYK4LShf4WbNsUv25 5Ckg== X-Gm-Message-State: AOJu0YySDg3v5l2M3CViSQF1nu0QjUsVmxEaneONOpDZzkUwCQ8ku/uh OW+O2Hick0iXdSekDQKOj1XOVCgeAUG4klRt0YXx+2KoWAdSG6AhNyhVPEX4z8MTuLSFtjHfl2s = X-Google-Smtp-Source: AGHT+IGAgyx1PaDPhNLYCwCRj3o6ojc6hXaRBBgDPYm0EJK6QiEXCPGoT4nwpMKiu530OxY/5pIEYQ== X-Received: by 2002:a05:600c:3544:b0:420:29dd:84d0 with SMTP id 5b1f17b1804b1-42029dd8836mr78257075e9.29.1716191360839; Mon, 20 May 2024 00:49:20 -0700 (PDT) Received: from poulhies-Precision-5550.lan ([2001:861:3382:1a90:de37:8b1c:1f33:2610]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-41f88111033sm446892175e9.34.2024.05.20.00.49.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 00:49:20 -0700 (PDT) From: =?UTF-8?q?Marc=20Poulhi=C3=A8s?= To: gcc-patches@gcc.gnu.org Cc: Gary Dismukes Subject: [COMMITTED 12/30] ada: Resolve ACATS compilation and execution issues with container aggregates Date: Mon, 20 May 2024 09:48:38 +0200 Message-ID: <20240520074858.222435-12-poulhies@adacore.com> X-Mailer: git-send-email 2.43.2 In-Reply-To: <20240520074858.222435-1-poulhies@adacore.com> References: <20240520074858.222435-1-poulhies@adacore.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_ASCII_DIVIDERS,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: From: Gary Dismukes This change set addresses various compilation and execution problems encountered in the draft ACATS tests for container aggregates: C435001 (container aggregates with Assign_Indexed) C435002 (container aggregates with Add_Unnamed) C435003 (container aggregates with Add_Named) C435004 (container aggregates with Assign_Indexed and Add_Unnamed) gcc/ada/ * exp_aggr.adb (Expand_Container_Aggregate): Add top-level variables Choice_{Lo|Hi} and Int_Choice_{Lo|Hi} used for determining the low and high bounds of component association choices. Replace code for determining whether we have an indexed aggregate with call to new function Sem_Aggr.Is_Indexed_Aggregate. Remove test of whether Empty_Subp is a function, since it must be a function. Move Default and Count_Type to be locals of a new block enclosing the code that creates the object to hold the aggregate length, and set them according to the default and type of the Empty function's parameter when present (and to Empty and Standard_Natural otherwise). Use Siz_Exp for the aggregate length when set, and use Empty's default length when available, and use zero for the length otherwise. In generating the call to the New_Indexed function, use the determined lower and upper bounds if determined earlier by Aggregate_Size, and otherwise compute those from the index type's lower bound and the determined aggregate length. In the case where a call to Empty is generated and the function has a formal parameter, pass the value saved in Siz_Decl (otherwise the parameter list is empty). Remove code specific to making a parameterless call to the Empty function. Extend the code for handling positional container aggregates to account for types that define Assign_Indexed, rather than just Add_Unnamed, and in the case of indexed aggregates, create a temporary object to hold values of the aggregate's key index, and initialize and increment that temporary for each call generated to the Assign_Indexed procedure. For named container aggregates that have key choices given by ranges, call Expand_Range_Component to generate a loop that will call the appropriate insertion procedure for each value of the range. For indexed aggregates with a Component_Associations list, set and use the Assign_Indexed procedure for each component association, whether or not there's an iterator specification. (Add_Range_Size): Add code to determine the low and high bounds of the range and capture those in up-level variables when their value is less than or greater than (respectively) the current minimum and maximum bounds values. (Aggregate_Size): Separately handle the case where a single choice is of a discrete type, and call Add_Range_Size to take its value into consideration for determination of min and max bounds of the aggregate. Add comments in a couple of places. (Build_Siz_Exp): Remove the last sentence and "???" from the comment that talks about accumulating nonstatic sizes, since that sentence seems to be obsolete. Record the low and high bound values in Choice_Lo and Choice_Hi in the case of a nonstatic range. (Expand_Iterated_Component): Set the Defining_Identifier of the iterator specification to the Loop_Id in the N_Iterated_Component_Association case. (Expand_Range_Component): Procedure unnested from the block handling indexed aggregates in Expand_Container_Aggregate, and moved to top level of that procedure so it can also be called for Add_Named cases. A formal parameter Insert_Op is added, and existing calls to this procedure are changed to pass the appropriate insertion procedure's Entity. * sem_aggr.ads: Add with_clause for Sinfo.Nodes. (Is_Indexed_Aggregate): New function for use by Resolve_Container_Aggregate and Expand_Container_Aggregate. * sem_aggr.adb: Add with_clause for Sem_Ch5. Move with_clause for Sinfo.Nodes to sem_aggr.ads. (Is_Indexed_Aggregate): New function to determine whether a container aggregate is a container aggregate (replacing local variable of the same name in Resolve_Container_Aggregate). (Resolve_Iterated_Association): Remove part of comment saying that a Key_Expression is always present. Set Parent field of the copy of a component association with a loop parameter specification. On the setting of Loop_Param_Id, account for a Loop_Parameter_Specification being changed into an Iterator_Specification as a result of being analyzed. Only call Preanalyze_And_Resolve on Key_Expr when a key expression is actually present. Remove loop for handling choices for the case of an N_Component_Association with a Defining_Identifier (there shouldn't be more than one choice in this case, and add an assertion to ensure that). Also add code here to handle the case where the choice is a function call, creating an iterator_specification analyzing it, and call Resolve_Iterated_Association recursively to process it. Add error check to enforce RM22 4.3.5(27), which requires that the type of the loop parameter must be the same as the key type when there is no key expression and the aggregate is an indexed aggregate or has an Add_Named op. (Resolve_Container_Aggregate): In the Add_Unnamed case, call Resolve_Iterated_Association for both N_Iterated_Element_Association and N_Component_Association (rather than just the latter). Remove error check for nonstatic choices in component associations in Add_Named cases (multiple named nonstatic associations are fine except in indexed aggregates). Remove local variable Is_Indexed_Aggregate, replaced with new library-level function of the same name, and add test of Is_Indexed_Aggregate in the case where the aggregate type has an Assign_Indexed operation, as a guard for doing error checks for indexed aggregates. For indexed aggregate resolution, do not call Analyze_And_Resolve on the expression of an N_Component_Association in the "box association" case. Move error checks for indexed aggregates with iterated associations that flag cases where an association is a loop_parameter_specification with an iterator filter or a key expression (violation of RM22 4.3.5(28/5)), from the loop that checks for contiguous and nonoverlapping choices and into the preceding association loop after the call to Resolve_Iterated_Association. The RM reference is added to the error-message strings. Tested on x86_64-pc-linux-gnu, committed on master. --- gcc/ada/exp_aggr.adb | 444 ++++++++++++++++++++++++++----------------- gcc/ada/sem_aggr.adb | 382 +++++++++++++++++++++++++++---------- gcc/ada/sem_aggr.ads | 16 ++ 3 files changed, 569 insertions(+), 273 deletions(-) diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb index 8a3d1685cb3..6208b49ffd9 100644 --- a/gcc/ada/exp_aggr.adb +++ b/gcc/ada/exp_aggr.adb @@ -6614,8 +6614,6 @@ package body Exp_Aggr is Temp : constant Entity_Id := Make_Temporary (Loc, 'C', N); Comp : Node_Id; - Decl : Node_Id; - Default : Node_Id; Init_Stat : Node_Id; Siz : Int; @@ -6623,7 +6621,15 @@ package body Exp_Aggr is -- static and requires a dynamic evaluation. Siz_Decl : Node_Id; Siz_Exp : Node_Id := Empty; - Count_Type : Entity_Id; + + -- These variables are used to determine the smallest and largest + -- choice values. Choice_Lo and Choice_Hi are passed to the New_Indexed + -- function, for allocating an indexed aggregate object. + + Choice_Lo : Node_Id := Empty; + Choice_Hi : Node_Id := Empty; + Int_Choice_Lo : Int; + Int_Choice_Hi : Int; Is_Indexed_Aggregate : Boolean := False; @@ -6649,6 +6655,14 @@ package body Exp_Aggr is -- given either by a loop parameter specification or an iterator -- specification. + function Expand_Range_Component + (Rng : Node_Id; + Expr : Node_Id; + Insert_Op : Entity_Id) return Node_Id; + -- Transform a component association with a range into an explicit loop + -- that calls the appropriate operation Insert_Op to add the value of + -- Expr to each container element with an index in the range. + -------------------- -- Aggregate_Size -- -------------------- @@ -6668,16 +6682,32 @@ package body Exp_Aggr is -------------------- procedure Add_Range_Size is + Range_Int_Lo : Int; + Range_Int_Hi : Int; + begin -- The bounds of the discrete range are integers or enumeration -- literals if Nkind (Lo) = N_Integer_Literal then - Siz := Siz + UI_To_Int (Intval (Hi)) - - UI_To_Int (Intval (Lo)) + 1; + Range_Int_Lo := UI_To_Int (Intval (Lo)); + Range_Int_Hi := UI_To_Int (Intval (Hi)); + else - Siz := Siz + UI_To_Int (Enumeration_Pos (Hi)) - - UI_To_Int (Enumeration_Pos (Lo)) + 1; + Range_Int_Lo := UI_To_Int (Enumeration_Pos (Lo)); + Range_Int_Hi := UI_To_Int (Enumeration_Pos (Hi)); + end if; + + Siz := Siz + Range_Int_Hi - Range_Int_Lo + 1; + + if No (Choice_Lo) or else Range_Int_Lo < Int_Choice_Lo then + Choice_Lo := Lo; + Int_Choice_Lo := Range_Int_Lo; + end if; + + if No (Choice_Hi) or else Range_Int_Hi > Int_Choice_Hi then + Choice_Hi := Hi; + Int_Choice_Hi := Range_Int_Hi; end if; end Add_Range_Size; @@ -6736,6 +6766,8 @@ package body Exp_Aggr is Hi := High_Bound (Choice); Add_Range_Size; + -- Choice is subtype_mark; add range based on its bounds + elsif Is_Entity_Name (Choice) and then Is_Type (Entity (Choice)) then @@ -6748,6 +6780,15 @@ package body Exp_Aggr is New_Copy_Tree (Lo), New_Copy_Tree (Hi))); + -- Choice is a single discrete value + + elsif Is_Discrete_Type (Etype (Choice)) then + Lo := Choice; + Hi := Choice; + Add_Range_Size; + + -- Choice is a single value of some nondiscrete type + else -- Single choice (syntax excludes a subtype -- indication). @@ -6812,10 +6853,8 @@ package body Exp_Aggr is return Siz; -- The possibility of having multiple associations with nonstatic - -- ranges (plus static ranges) means that in general we really - -- should be accumulating a sum of the various sizes. The current - -- code can end up overwriting Siz_Exp on subsequent associations - -- (plus won't account for associations with static ranges). ??? + -- ranges (plus static ranges) means that in general we have to + -- accumulate a sum of the various sizes. else Temp_Siz_Exp := @@ -6827,6 +6866,12 @@ package body Exp_Aggr is Right_Opnd => Make_Integer_Literal (Loc, 1)); + -- Capture the nonstatic bounds, for later use in passing on + -- the call to New_Indexed. + + Choice_Lo := Lo; + Choice_Hi := Hi; + -- Include this nonstatic length in the total length being -- accumulated in Siz_Exp. @@ -6939,6 +6984,8 @@ package body Exp_Aggr is L_Iteration_Scheme := Make_Iteration_Scheme (Loc, Iterator_Specification => Iterator_Specification (Comp)); + Set_Defining_Identifier + (Iterator_Specification (L_Iteration_Scheme), Loop_Id); else -- Loop_Parameter_Specification is parsed with a choice list. @@ -7004,6 +7051,45 @@ package body Exp_Aggr is end Expand_Iterated_Component; + ---------------------------- + -- Expand_Range_Component -- + ---------------------------- + + function Expand_Range_Component + (Rng : Node_Id; + Expr : Node_Id; + Insert_Op : Entity_Id) return Node_Id + is + Loop_Id : constant Entity_Id := + Make_Temporary (Loc, 'T'); + + L_Iteration_Scheme : Node_Id; + Stats : List_Id; + + begin + L_Iteration_Scheme := + Make_Iteration_Scheme (Loc, + Loop_Parameter_Specification => + Make_Loop_Parameter_Specification (Loc, + Defining_Identifier => Loop_Id, + Discrete_Subtype_Definition => New_Copy_Tree (Rng))); + + Stats := New_List + (Make_Procedure_Call_Statement (Loc, + Name => + New_Occurrence_Of (Insert_Op, Loc), + Parameter_Associations => + New_List (New_Occurrence_Of (Temp, Loc), + New_Occurrence_Of (Loop_Id, Loc), + New_Copy_Tree (Expr)))); + + return Make_Implicit_Loop_Statement + (Node => N, + Identifier => Empty, + Iteration_Scheme => L_Iteration_Scheme, + Statements => Stats); + end Expand_Range_Component; + -- Start of processing for Expand_Container_Aggregate begin @@ -7013,34 +7099,9 @@ package body Exp_Aggr is -- Determine whether this is an indexed aggregate (see RM 4.3.5(25/5)) - if Present (New_Indexed_Subp) then - if No (Add_Unnamed_Subp) then - Is_Indexed_Aggregate := True; - - else - declare - Comp_Assns : constant List_Id := Component_Associations (N); - Comp_Assn : Node_Id; - - begin - if not Is_Empty_List (Comp_Assns) then - - -- It suffices to look at the first association to determine - -- whether the aggregate is an indexed aggregate. - - Comp_Assn := First (Comp_Assns); - - if Nkind (Comp_Assn) = N_Component_Association - or else - (Nkind (Comp_Assn) = N_Iterated_Component_Association - and then Present (Defining_Identifier (Comp_Assn))) - then - Is_Indexed_Aggregate := True; - end if; - end if; - end; - end if; - end if; + Is_Indexed_Aggregate + := Sem_Aggr.Is_Indexed_Aggregate + (N, Add_Unnamed_Subp, New_Indexed_Subp); -- The constructor for bounded containers is a function with -- a parameter that sets the size of the container. If the @@ -7049,35 +7110,50 @@ package body Exp_Aggr is Siz := Aggregate_Size; - --------------------- - -- Empty function -- - --------------------- - - if Ekind (Entity (Empty_Subp)) = E_Function - and then Present (First_Formal (Entity (Empty_Subp))) - then - Default := Default_Value (First_Formal (Entity (Empty_Subp))); + declare + Count_Type : Entity_Id := Standard_Natural; + Default : Node_Id := Empty; + Empty_First_Formal : constant Entity_Id + := First_Formal (Entity (Empty_Subp)); + Param_List : List_Id; - -- If aggregate size is not static, we can use default value - -- of formal parameter for allocation. We assume that this - -- (implementation-dependent) value is static, even though - -- the AI does not require it. + begin + -- If aggregate size is not static, we use the default value of the + -- Empty operation's formal parameter for the allocation. We assume + -- that this (implementation-dependent) value is static, even though + -- the AI does not require it. + + if Present (Empty_First_Formal) then + Default := Default_Value (Empty_First_Formal); + Count_Type := Etype (Empty_First_Formal); + end if; - -- Create declaration for size: a constant literal in the simple - -- case, an expression if iterated component associations may be - -- involved, the default otherwise. + -- Create an object initialized by the aggregate's determined size + -- (number of elements): a constant literal in the simple case, an + -- expression if iterated component associations may be involved, + -- and the default otherwise. - Count_Type := Etype (First_Formal (Entity (Empty_Subp))); if Siz = -1 then - if No (Siz_Exp) then + if No (Siz_Exp) + and Present (Default) + then Siz := UI_To_Int (Intval (Default)); Siz_Exp := Make_Integer_Literal (Loc, Siz); - else + elsif Present (Siz_Exp) then Siz_Exp := Make_Type_Conversion (Loc, Subtype_Mark => New_Occurrence_Of (Count_Type, Loc), Expression => Siz_Exp); + + -- If the length isn't known and there's not a default, then use + -- zero for the initial container length. + + else + Siz_Exp := Make_Type_Conversion (Loc, + Subtype_Mark => + New_Occurrence_Of (Count_Type, Loc), + Expression => Make_Integer_Literal (Loc, 0)); end if; else @@ -7100,21 +7176,30 @@ package body Exp_Aggr is Entity (Assign_Indexed_Subp); Index_Type : constant Entity_Id := Etype (Next_Formal (First_Formal (Insert))); - Index : Node_Id; begin - Index := Make_Op_Add (Loc, - Left_Opnd => New_Copy_Tree (Type_Low_Bound (Index_Type)), - Right_Opnd => - Make_Op_Subtract (Loc, - Left_Opnd => Make_Type_Conversion (Loc, - Subtype_Mark => - New_Occurrence_Of (Index_Type, Loc), - Expression => - New_Occurrence_Of - (Defining_Identifier (Siz_Decl), - Loc)), - Right_Opnd => Make_Integer_Literal (Loc, 1))); + if No (Choice_Lo) then + pragma Assert (No (Choice_Hi)); + + Choice_Lo := New_Copy_Tree (Type_Low_Bound (Index_Type)); + + Choice_Hi := Make_Op_Add (Loc, + Left_Opnd => New_Copy_Tree (Type_Low_Bound (Index_Type)), + Right_Opnd => + Make_Op_Subtract (Loc, + Left_Opnd => Make_Type_Conversion (Loc, + Subtype_Mark => + New_Occurrence_Of (Index_Type, Loc), + Expression => + New_Occurrence_Of + (Defining_Identifier (Siz_Decl), + Loc)), + Right_Opnd => Make_Integer_Literal (Loc, 1))); + + else + Choice_Lo := New_Copy_Tree (Choice_Lo); + Choice_Hi := New_Copy_Tree (Choice_Hi); + end if; Init_Stat := Make_Object_Declaration (Loc, @@ -7124,52 +7209,33 @@ package body Exp_Aggr is Name => New_Occurrence_Of (Entity (New_Indexed_Subp), Loc), Parameter_Associations => - New_List ( - New_Copy_Tree (Type_Low_Bound (Index_Type)), - Index))); + New_List (Choice_Lo, Choice_Hi))); end; - -- Otherwise we generate a call to the Empty operation, passing - -- the determined number of elements as saved in Siz_Decl. + -- Otherwise we generate a call to the Empty function, passing the + -- determined number of elements as saved in Siz_Decl if the function + -- has a formal parameter, and otherwise making a parameterless call. else + if Present (Empty_First_Formal) then + Param_List := + New_List + (New_Occurrence_Of (Defining_Identifier (Siz_Decl), Loc)); + else + Param_List := No_List; + end if; + Init_Stat := Make_Object_Declaration (Loc, Defining_Identifier => Temp, Object_Definition => New_Occurrence_Of (Typ, Loc), Expression => Make_Function_Call (Loc, Name => New_Occurrence_Of (Entity (Empty_Subp), Loc), - Parameter_Associations => - New_List - (New_Occurrence_Of - (Defining_Identifier (Siz_Decl), Loc)))); + Parameter_Associations => Param_List)); end if; Append (Init_Stat, Aggr_Code); - - -- The container will grow dynamically. Create a declaration for - -- the object, and initialize it from a call to the parameterless - -- Empty function. - - else - pragma Assert (Ekind (Entity (Empty_Subp)) = E_Function); - - Decl := - Make_Object_Declaration (Loc, - Defining_Identifier => Temp, - Object_Definition => New_Occurrence_Of (Typ, Loc)); - - Insert_Action (N, Decl); - - -- The Empty entity is a parameterless function - - Init_Stat := Make_Assignment_Statement (Loc, - Name => New_Occurrence_Of (Temp, Loc), - Expression => Make_Function_Call (Loc, - Name => New_Occurrence_Of (Entity (Empty_Subp), Loc))); - - Append (Init_Stat, Aggr_Code); - end if; + end; -- Report warning on infinite recursion if an empty container aggregate -- appears in the return statement of its Empty function. @@ -7192,24 +7258,88 @@ package body Exp_Aggr is -- Positional aggregate -- --------------------------- - -- If the aggregate is positional the aspect must include - -- an Add_Unnamed subprogram. + -- If the aggregate is positional, then the aspect must include + -- an Add_Unnamed or Assign_Indexed procedure. - if Present (Add_Unnamed_Subp) then + if not Is_Null_Aggregate (N) + and then + (Present (Add_Unnamed_Subp) or else Present (Assign_Indexed_Subp)) + then if Present (Expressions (N)) then declare - Insert : constant Entity_Id := Entity (Add_Unnamed_Subp); + Insert : constant Entity_Id := + (if Is_Indexed_Aggregate + then Entity (Assign_Indexed_Subp) + else Entity (Add_Unnamed_Subp)); Comp : Node_Id; Stat : Node_Id; + Param_List : List_Id; + Key_Type : Entity_Id; + Key_Index : Entity_Id; begin + -- For an indexed aggregate, use Etype of the Assign_Indexed + -- procedure's second formal as the key type, and declare an + -- index object of that type, which will iterate over the key + -- type values while traversing the component associations. + + if Is_Indexed_Aggregate then + Key_Type := + Etype (Next_Formal + (First_Formal (Entity (Assign_Indexed_Subp)))); + + Key_Index := Make_Temporary (Loc, 'I', N); + + Append_To (Aggr_Code, + Make_Object_Declaration (Loc, + Defining_Identifier => Key_Index, + Object_Definition => + New_Occurrence_Of (Key_Type, Loc))); + end if; + Comp := First (Expressions (N)); while Present (Comp) loop + if Is_Indexed_Aggregate then + + -- Generate an assignment to set the first key value of + -- the key index object from the key type's lower bound. + + if Comp = First (Expressions (N)) then + Append_To (Aggr_Code, + Make_Assignment_Statement (Loc, + Name => New_Occurrence_Of (Key_Index, Loc), + Expression => + New_Copy (Type_Low_Bound (Key_Type)))); + + -- Generate an assignment to increment the key value + -- for the subsequent component assignments. + + else + Append_To (Aggr_Code, + Make_Assignment_Statement (Loc, + Name => New_Occurrence_Of (Key_Index, Loc), + Expression => + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Key_Type, Loc), + Attribute_Name => Name_Succ, + Expressions => New_List ( + New_Occurrence_Of (Key_Index, Loc))))); + end if; + + Param_List := + New_List (New_Occurrence_Of (Temp, Loc), + New_Occurrence_Of (Key_Index, Loc), + New_Copy_Tree (Comp)); + else + Param_List := + New_List (New_Occurrence_Of (Temp, Loc), + New_Copy_Tree (Comp)); + end if; + Stat := Make_Procedure_Call_Statement (Loc, Name => New_Occurrence_Of (Insert, Loc), - Parameter_Associations => - New_List (New_Occurrence_Of (Temp, Loc), - New_Copy_Tree (Comp))); + Parameter_Associations => Param_List); Append (Stat, Aggr_Code); Next (Comp); end loop; @@ -7221,7 +7351,9 @@ package body Exp_Aggr is elsif not Is_Indexed_Aggregate then Comp := First (Component_Associations (N)); while Present (Comp) loop - if Nkind (Comp) = N_Iterated_Component_Association then + if Nkind (Comp) = N_Iterated_Component_Association + or else Nkind (Comp) = N_Iterated_Element_Association + then Expand_Iterated_Component (Comp); end if; Next (Comp); @@ -7252,12 +7384,23 @@ package body Exp_Aggr is Key := First (Choices (Comp)); while Present (Key) loop - Stat := Make_Procedure_Call_Statement (Loc, - Name => New_Occurrence_Of (Insert, Loc), - Parameter_Associations => - New_List (New_Occurrence_Of (Temp, Loc), - New_Copy_Tree (Key), - New_Copy_Tree (Expression (Comp)))); + if Nkind (Key) = N_Range then + + -- Create loop for the specified range, with copies of + -- the expression. + + Stat := Expand_Range_Component + (Key, Expression (Comp), Insert); + + else + Stat := Make_Procedure_Call_Statement (Loc, + Name => New_Occurrence_Of (Insert, Loc), + Parameter_Associations => + New_List (New_Occurrence_Of (Temp, Loc), + New_Copy_Tree (Key), + New_Copy_Tree (Expression (Comp)))); + end if; + Append (Stat, Aggr_Code); Next (Key); @@ -7285,57 +7428,11 @@ package body Exp_Aggr is and then not Is_Empty_List (Component_Associations (N)) then declare - - function Expand_Range_Component - (Rng : Node_Id; - Expr : Node_Id) return Node_Id; - -- Transform a component association with a range into an - -- explicit loop. If the choice is a subtype name, it is - -- rewritten as a range with the corresponding bounds, which - -- are known to be static. - + Insert : constant Entity_Id := Entity (Assign_Indexed_Subp); Comp : Node_Id; Stat : Node_Id; Key : Node_Id; - ---------------------------- - -- Expand_Range_Component -- - ---------------------------- - - function Expand_Range_Component - (Rng : Node_Id; - Expr : Node_Id) return Node_Id - is - Loop_Id : constant Entity_Id := - Make_Temporary (Loc, 'T'); - - L_Iteration_Scheme : Node_Id; - Stats : List_Id; - - begin - L_Iteration_Scheme := - Make_Iteration_Scheme (Loc, - Loop_Parameter_Specification => - Make_Loop_Parameter_Specification (Loc, - Defining_Identifier => Loop_Id, - Discrete_Subtype_Definition => New_Copy_Tree (Rng))); - - Stats := New_List - (Make_Procedure_Call_Statement (Loc, - Name => - New_Occurrence_Of (Entity (Assign_Indexed_Subp), Loc), - Parameter_Associations => - New_List (New_Occurrence_Of (Temp, Loc), - New_Occurrence_Of (Loop_Id, Loc), - New_Copy_Tree (Expr)))); - - return Make_Implicit_Loop_Statement - (Node => N, - Identifier => Empty, - Iteration_Scheme => L_Iteration_Scheme, - Statements => Stats); - end Expand_Range_Component; - begin pragma Assert (No (Expressions (N))); @@ -7357,20 +7454,20 @@ package body Exp_Aggr is elsif Nkind (Key) = N_Range then - -- Create loop for tne specified range, + -- Create loop for the specified range, -- with copies of the expression. Stat := - Expand_Range_Component (Key, Expression (Comp)); + Expand_Range_Component + (Key, Expression (Comp), Insert); else Stat := Make_Procedure_Call_Statement (Loc, - Name => New_Occurrence_Of - (Entity (Assign_Indexed_Subp), Loc), - Parameter_Associations => - New_List (New_Occurrence_Of (Temp, Loc), - New_Copy_Tree (Key), - New_Copy_Tree (Expression (Comp)))); + Name => New_Occurrence_Of (Insert, Loc), + Parameter_Associations => + New_List (New_Occurrence_Of (Temp, Loc), + New_Copy_Tree (Key), + New_Copy_Tree (Expression (Comp)))); end if; Append (Stat, Aggr_Code); @@ -7384,10 +7481,11 @@ package body Exp_Aggr is -- positional insertion procedure. if No (Iterator_Specification (Comp)) then - Add_Named_Subp := Assign_Indexed_Subp; Add_Unnamed_Subp := Empty; end if; + Add_Named_Subp := Assign_Indexed_Subp; + Expand_Iterated_Component (Comp); end if; diff --git a/gcc/ada/sem_aggr.adb b/gcc/ada/sem_aggr.adb index 14c68b5eaf3..658b3a4634c 100644 --- a/gcc/ada/sem_aggr.adb +++ b/gcc/ada/sem_aggr.adb @@ -49,6 +49,7 @@ with Sem_Aux; use Sem_Aux; with Sem_Case; use Sem_Case; with Sem_Cat; use Sem_Cat; with Sem_Ch3; use Sem_Ch3; +with Sem_Ch5; use Sem_Ch5; with Sem_Ch8; use Sem_Ch8; with Sem_Ch13; use Sem_Ch13; with Sem_Dim; use Sem_Dim; @@ -58,7 +59,6 @@ with Sem_Util; use Sem_Util; with Sem_Type; use Sem_Type; with Sem_Warn; use Sem_Warn; with Sinfo; use Sinfo; -with Sinfo.Nodes; use Sinfo.Nodes; with Sinfo.Utils; use Sinfo.Utils; with Snames; use Snames; with Stringt; use Stringt; @@ -781,6 +781,102 @@ package body Sem_Aggr is end if; end Is_Deep_Choice; + -------------------------- + -- Is_Indexed_Aggregate -- + -------------------------- + + function Is_Indexed_Aggregate + (N : N_Aggregate_Id; + Add_Unnamed : Node_Id; + New_Indexed : Node_Id) return Boolean + is + begin + if Present (New_Indexed) + and then not Is_Null_Aggregate (N) + then + if No (Add_Unnamed) then + return True; + + else + declare + Comp_Assns : constant List_Id := Component_Associations (N); + Comp_Assn : Node_Id; + + begin + if not Is_Empty_List (Comp_Assns) then + + -- It suffices to look at the first association to determine + -- whether the aggregate is an indexed aggregate. + + Comp_Assn := First (Comp_Assns); + + -- Test for the component association being either: + -- + -- 1) an N_Component_Association node, in which case there + -- is a list of choices (the "key choices"); + -- + -- or else: + -- + -- 2) an N_Iterated_Component_Association node that has + -- a Defining_Identifier, in which case it has + -- Discrete_Choices that effectively make it + -- equivalent to a Loop_Parameter_Specification; + -- + -- or else: + -- + -- 3) an N_Iterated_Element_Association node with + -- a Loop_Parameter_Specification with a discrete + -- subtype or range. + -- + -- This basically corresponds to the definition of indexed + -- aggregates (in RM22 4.3.5(25/5)), but the GNAT tree + -- representation doesn't always directly match the RM + -- syntax for various reasons. + + if Nkind (Comp_Assn) = N_Component_Association + or else + (Nkind (Comp_Assn) = N_Iterated_Component_Association + and then Present (Defining_Identifier (Comp_Assn))) + then + return True; + + -- In the case of an iterated_element_association with a + -- loop_parameter_specification, we have to look deeper to + -- confirm that it is not actually an iterator_specification + -- masquerading as a loop_parameter_specification. Those can + -- share syntax (for example, having the iterator of form + -- "for C in ") and a rewrite into an + -- iterator_specification can happen later. + + elsif Nkind (Comp_Assn) = N_Iterated_Element_Association + and then Present (Loop_Parameter_Specification (Comp_Assn)) + then + declare + Loop_Parm_Spec : constant Node_Id := + Loop_Parameter_Specification (Comp_Assn); + Discr_Subt_Defn : constant Node_Id := + Discrete_Subtype_Definition (Loop_Parm_Spec); + begin + if Nkind (Discr_Subt_Defn) = N_Range + or else + Nkind (Discr_Subt_Defn) = N_Subtype_Indication + or else + (Is_Entity_Name (Discr_Subt_Defn) + and then + Is_Type (Entity (Discr_Subt_Defn))) + then + return True; + end if; + end; + end if; + end if; + end; + end if; + end if; + + return False; + end Is_Indexed_Aggregate; + ------------------------- -- Is_Others_Aggregate -- ------------------------- @@ -3227,22 +3323,23 @@ package body Sem_Aggr is Key_Type : Entity_Id; Elmt_Type : Entity_Id) is - Loc : constant Source_Ptr := Sloc (N); - Choice : Node_Id; - Copy : Node_Id; - Ent : Entity_Id; - Expr : Node_Id; - Key_Expr : Node_Id; - Id : Entity_Id; - Id_Name : Name_Id; - Typ : Entity_Id := Empty; + Loc : constant Source_Ptr := Sloc (N); + Choice : Node_Id; + Copy : Node_Id; + Ent : Entity_Id; + Expr : Node_Id; + Key_Expr : Node_Id := Empty; + Id : Entity_Id; + Id_Name : Name_Id; + Typ : Entity_Id := Empty; + Loop_Param_Id : Entity_Id := Empty; begin Error_Msg_Ada_2022_Feature ("iterated component", Loc); -- If this is an Iterated_Element_Association then either a -- an Iterator_Specification or a Loop_Parameter specification - -- is present. In both cases a Key_Expression is present. + -- is present. if Nkind (Comp) = N_Iterated_Element_Association then @@ -3258,18 +3355,27 @@ package body Sem_Aggr is if Present (Loop_Parameter_Specification (Comp)) then Copy := Copy_Separate_Tree (Comp); + Set_Parent (Copy, Parent (Comp)); Analyze (Loop_Parameter_Specification (Copy)); - Id_Name := Chars (Defining_Identifier - (Loop_Parameter_Specification (Comp))); + if Present (Iterator_Specification (Copy)) then + Loop_Param_Id := + Defining_Identifier (Iterator_Specification (Copy)); + else + Loop_Param_Id := + Defining_Identifier (Loop_Parameter_Specification (Copy)); + end if; + + Id_Name := Chars (Loop_Param_Id); else Copy := Copy_Separate_Tree (Iterator_Specification (Comp)); Analyze (Copy); - Id_Name := Chars (Defining_Identifier - (Iterator_Specification (Comp))); + Loop_Param_Id := Defining_Identifier (Copy); + + Id_Name := Chars (Loop_Param_Id); end if; -- Key expression must have the type of the key. We preanalyze @@ -3278,10 +3384,12 @@ package body Sem_Aggr is -- corresponding loop. Key_Expr := Key_Expression (Comp); - Preanalyze_And_Resolve (New_Copy_Tree (Key_Expr), Key_Type); + if Present (Key_Expr) then + Preanalyze_And_Resolve (New_Copy_Tree (Key_Expr), Key_Type); + end if; End_Scope; - Typ := Key_Type; + Typ := Etype (Loop_Param_Id); elsif Present (Iterator_Specification (Comp)) then -- Create a temporary scope to avoid some modifications from @@ -3294,9 +3402,12 @@ package body Sem_Aggr is Set_Parent (Ent, Parent (Comp)); Push_Scope (Ent); - Copy := Copy_Separate_Tree (Iterator_Specification (Comp)); - Id_Name := - Chars (Defining_Identifier (Iterator_Specification (Comp))); + Copy := Copy_Separate_Tree (Iterator_Specification (Comp)); + + Loop_Param_Id := + Defining_Identifier (Iterator_Specification (Comp)); + + Id_Name := Chars (Loop_Param_Id); Preanalyze (Copy); @@ -3307,28 +3418,58 @@ package body Sem_Aggr is else Choice := First (Discrete_Choices (Comp)); - while Present (Choice) loop - Analyze (Choice); + -- This is an N_Component_Association with a Defining_Identifier + -- and Discrete_Choice_List, but the latter can only have a single + -- choice, as it's a stand-in for a Loop_Parameter_Specification + -- (or possibly even an Iterator_Specification, see below). - -- Choice can be a subtype name, a range, or an expression + pragma Assert (No (Next (Choice))); - if Is_Entity_Name (Choice) - and then Is_Type (Entity (Choice)) - and then Base_Type (Entity (Choice)) = Base_Type (Key_Type) - then - null; + Analyze (Choice); - elsif Present (Key_Type) then - Analyze_And_Resolve (Choice, Key_Type); - Typ := Key_Type; - else - Typ := Etype (Choice); -- assume unique for now - end if; + -- Choice can be a subtype name, a range, or an expression - Next (Choice); - end loop; + if Is_Entity_Name (Choice) + and then Is_Type (Entity (Choice)) + and then Base_Type (Entity (Choice)) = Base_Type (Key_Type) + then + null; + + elsif Nkind (Choice) = N_Function_Call then + declare + I_Spec : constant Node_Id := + Make_Iterator_Specification (Sloc (N), + Defining_Identifier => + Relocate_Node (Defining_Identifier (Comp)), + Name => New_Copy_Tree (Choice), + Reverse_Present => False, + Iterator_Filter => Empty, + Subtype_Indication => Empty); + begin + Set_Iterator_Specification (Comp, I_Spec); + Set_Defining_Identifier (Comp, Empty); + + Analyze_Iterator_Specification + (Iterator_Specification (Comp)); + + Resolve_Iterated_Association (Comp, Key_Type, Elmt_Type); + -- Recursive call to expand association as iterator_spec + + return; + end; + + elsif Present (Key_Type) then + Analyze_And_Resolve (Choice, Key_Type); + Typ := Key_Type; + + else + Typ := Etype (Choice); -- assume unique for now + end if; + + Loop_Param_Id := + Defining_Identifier (Comp); - Id_Name := Chars (Defining_Identifier (Comp)); + Id_Name := Chars (Loop_Param_Id); end if; -- Create a scope in which to introduce an index, which is usually @@ -3358,6 +3499,21 @@ package body Sem_Aggr is Set_Scope (Id, Ent); Set_Referenced (Id); + -- Check for violation of 4.3.5(27/5) + + if No (Key_Expr) + and then Present (Key_Type) + and then + (Is_Indexed_Aggregate (N, Add_Unnamed_Subp, New_Indexed_Subp) + or else Present (Add_Named_Subp)) + and then Base_Type (Key_Type) /= Base_Type (Typ) + then + Error_Msg_Node_2 := Key_Type; + Error_Msg_NE + ("loop parameter type & must be same as key type & " & + "(RM22 4.3.5(27))", Loop_Param_Id, Typ); + end if; + -- Analyze a copy of the expression, to verify legality. We use -- a copy because the expression will be analyzed anew when the -- enclosing aggregate is expanded, and the construct is rewritten @@ -3409,15 +3565,16 @@ package body Sem_Aggr is Comp : Node_Id := First (Component_Associations (N)); begin while Present (Comp) loop - if Nkind (Comp) /= - N_Iterated_Component_Association + if Nkind (Comp) in + N_Iterated_Component_Association | + N_Iterated_Element_Association then + Resolve_Iterated_Association + (Comp, Empty, Elmt_Type); + else Error_Msg_N ("illegal component association " & "for unnamed container aggregate", Comp); return; - else - Resolve_Iterated_Association - (Comp, Empty, Elmt_Type); end if; Next (Comp); @@ -3463,10 +3620,6 @@ package body Sem_Aggr is while Present (Choice) loop Analyze_And_Resolve (Choice, Key_Type); - if not Is_Static_Expression (Choice) then - Error_Msg_N ("choice must be static", Choice); - end if; - Next (Choice); end loop; @@ -3535,7 +3688,9 @@ package body Sem_Aggr is Next (Choice); end loop; - Analyze_And_Resolve (Expression (Comp), Comp_Type); + if not Box_Present (Comp) then + Analyze_And_Resolve (Expression (Comp), Comp_Type); + end if; elsif Nkind (Comp) in N_Iterated_Component_Association | @@ -3543,6 +3698,56 @@ package body Sem_Aggr is then Resolve_Iterated_Association (Comp, Index_Type, Comp_Type); + + -- Check the legality rule of RM22 4.3.5(28/5). Note that + -- Is_Indexed_Aggregate can change its status (to False) + -- as a result of calling Resolve_Iterated_Association, + -- due to possible expansion of iterator_specifications + -- there. + + if Is_Indexed_Aggregate + (N, Add_Unnamed_Subp, New_Indexed_Subp) + then + if Nkind (Comp) = N_Iterated_Element_Association then + if Present (Loop_Parameter_Specification (Comp)) + then + if Present (Iterator_Filter + (Loop_Parameter_Specification (Comp))) + then + Error_Msg_N + ("iterator filter not allowed " & + "in indexed aggregate (RM22 4.3.5(28))", + Iterator_Filter + (Loop_Parameter_Specification (Comp))); + return; + + elsif Present (Key_Expression (Comp)) then + Error_Msg_N + ("key expression not allowed " & + "in indexed aggregate (RM22 4.3.5(28))", + Key_Expression (Comp)); + return; + end if; + + elsif Present (Iterator_Specification (Comp)) then + Error_Msg_N + ("iterator specification not allowed " & + "in indexed aggregate (RM22 4.3.5(28))", + Iterator_Specification (Comp)); + return; + end if; + + elsif Nkind (Comp) = N_Iterated_Component_Association + and then Present (Iterator_Specification (Comp)) + then + Error_Msg_N + ("iterator specification not allowed " & + "in indexed aggregate (RM22 4.3.5(28))", + Iterator_Specification (Comp)); + return; + end if; + end if; + Num_Choices := Num_Choices + 1; end if; @@ -3569,67 +3774,44 @@ package body Sem_Aggr is begin Comp := First (Component_Associations (N)); while Present (Comp) loop - if Nkind (Comp) = N_Iterated_Element_Association then - if Present - (Loop_Parameter_Specification (Comp)) - then - if Present (Iterator_Filter - (Loop_Parameter_Specification (Comp))) - then - Error_Msg_N - ("iterator filter not allowed " & - "in indexed aggregate", Comp); - return; - - elsif Present (Key_Expression - (Loop_Parameter_Specification (Comp))) - then - Error_Msg_N - ("key expression not allowed " & - "in indexed aggregate", Comp); - return; - end if; - end if; - else - -- If Nkind is N_Iterated_Component_Association, - -- this corresponds to an iterator_specification - -- with a loop_parameter_specification, and we - -- have to pick up Discrete_Choices. In this case - -- there will be just one "choice", which will - -- typically be a range. + -- If Nkind is N_Iterated_Component_Association, + -- this corresponds to an iterator_specification + -- with a loop_parameter_specification, and we + -- have to pick up Discrete_Choices. In this case + -- there will be just one "choice", which will + -- typically be a range. - if Nkind (Comp) = N_Iterated_Component_Association - then - Choice := First (Discrete_Choices (Comp)); + if Nkind (Comp) = N_Iterated_Component_Association + then + Choice := First (Discrete_Choices (Comp)); - -- Case where there's a list of choices + -- Case where there's a list of choices - else - Choice := First (Choices (Comp)); - end if; + else + Choice := First (Choices (Comp)); + end if; - while Present (Choice) loop - Get_Index_Bounds (Choice, Lo, Hi); - Table (No_Choice).Choice := Choice; - Table (No_Choice).Lo := Lo; - Table (No_Choice).Hi := Hi; + while Present (Choice) loop + Get_Index_Bounds (Choice, Lo, Hi); + Table (No_Choice).Choice := Choice; + Table (No_Choice).Lo := Lo; + Table (No_Choice).Hi := Hi; - -- Verify staticness of value or range + -- Verify staticness of value or range - if not Is_Static_Expression (Lo) - or else not Is_Static_Expression (Hi) - then - Error_Msg_N - ("nonstatic expression for index " & - "for indexed aggregate", Choice); - return; - end if; + if not Is_Static_Expression (Lo) + or else not Is_Static_Expression (Hi) + then + Error_Msg_N + ("nonstatic expression for index " & + "for indexed aggregate", Choice); + return; + end if; - No_Choice := No_Choice + 1; - Next (Choice); - end loop; - end if; + No_Choice := No_Choice + 1; + Next (Choice); + end loop; Next (Comp); end loop; diff --git a/gcc/ada/sem_aggr.ads b/gcc/ada/sem_aggr.ads index 36827fa3267..36dc0ebc893 100644 --- a/gcc/ada/sem_aggr.ads +++ b/gcc/ada/sem_aggr.ads @@ -27,6 +27,7 @@ -- part of Sem_Res, but is split off since the aggregate code is so complex. with Einfo.Entities; use Einfo.Entities; +with Sinfo.Nodes; use Sinfo.Nodes; with Types; use Types; package Sem_Aggr is @@ -44,6 +45,21 @@ package Sem_Aggr is -- WARNING: There is a matching C declaration of this subprogram in fe.h + function Is_Indexed_Aggregate + (N : N_Aggregate_Id; + Add_Unnamed : Node_Id; + New_Indexed : Node_Id) return Boolean; + -- Returns True if N satisfies the criteria for being an indexed aggregate, + -- that is, N is a container aggregate whose type has an Aggregate aspect + -- that specifies a New_Indexed operation (it's Present), the aggregate + -- is not a null aggregate, and either the type doesn't specify Add_Unnamed + -- or there is a component association that is an N_Component_Association + -- or is an N_Iterated_Component_Association with a Defining_Identifier. + -- Returns False otherwise. The actuals for the Add_Unnamed and New_Indexed + -- formals must be nodes that are names denoting the subprograms specified + -- for those operations in the Aggregate aspect of the aggregate's type, + -- or else Empty if the operation was not specified. + function Is_Null_Aggregate (N : Node_Id) return Boolean; -- Returns True for a "[]" aggregate (an Ada 2022 feature), even after -- it has been transformed by expansion. Returns False otherwise. -- 2.43.2