* gcc.dg/predict-12.c: New testcase.
[official-gcc.git] / gcc / ada / sem_dim.adb
blob2bdf9e5a2c49785bc75d70605056df04288d3294
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- S E M _ D I M --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2011-2016, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Aspects; use Aspects;
27 with Atree; use Atree;
28 with Einfo; use Einfo;
29 with Errout; use Errout;
30 with Exp_Util; use Exp_Util;
31 with Lib; use Lib;
32 with Namet; use Namet;
33 with Nlists; use Nlists;
34 with Nmake; use Nmake;
35 with Opt; use Opt;
36 with Rtsfind; use Rtsfind;
37 with Sem; use Sem;
38 with Sem_Eval; use Sem_Eval;
39 with Sem_Res; use Sem_Res;
40 with Sem_Util; use Sem_Util;
41 with Sinfo; use Sinfo;
42 with Sinput; use Sinput;
43 with Snames; use Snames;
44 with Stand; use Stand;
45 with Stringt; use Stringt;
46 with Table;
47 with Tbuild; use Tbuild;
48 with Uintp; use Uintp;
49 with Urealp; use Urealp;
51 with GNAT.HTable;
53 package body Sem_Dim is
55 -------------------------
56 -- Rational Arithmetic --
57 -------------------------
59 type Whole is new Int;
60 subtype Positive_Whole is Whole range 1 .. Whole'Last;
62 type Rational is record
63 Numerator : Whole;
64 Denominator : Positive_Whole;
65 end record;
67 Zero : constant Rational := Rational'(Numerator => 0,
68 Denominator => 1);
70 No_Rational : constant Rational := Rational'(Numerator => 0,
71 Denominator => 2);
72 -- Used to indicate an expression that cannot be interpreted as a rational
73 -- Returned value of the Create_Rational_From routine when parameter Expr
74 -- is not a static representation of a rational.
76 -- Rational constructors
78 function "+" (Right : Whole) return Rational;
79 function GCD (Left, Right : Whole) return Int;
80 function Reduce (X : Rational) return Rational;
82 -- Unary operator for Rational
84 function "-" (Right : Rational) return Rational;
85 function "abs" (Right : Rational) return Rational;
87 -- Rational operations for Rationals
89 function "+" (Left, Right : Rational) return Rational;
90 function "-" (Left, Right : Rational) return Rational;
91 function "*" (Left, Right : Rational) return Rational;
92 function "/" (Left, Right : Rational) return Rational;
94 ------------------
95 -- System Types --
96 ------------------
98 Max_Number_Of_Dimensions : constant := 7;
99 -- Maximum number of dimensions in a dimension system
101 High_Position_Bound : constant := Max_Number_Of_Dimensions;
102 Invalid_Position : constant := 0;
103 Low_Position_Bound : constant := 1;
105 subtype Dimension_Position is
106 Nat range Invalid_Position .. High_Position_Bound;
108 type Name_Array is
109 array (Dimension_Position range
110 Low_Position_Bound .. High_Position_Bound) of Name_Id;
111 -- Store the names of all units within a system
113 No_Names : constant Name_Array := (others => No_Name);
115 type Symbol_Array is
116 array (Dimension_Position range
117 Low_Position_Bound .. High_Position_Bound) of String_Id;
118 -- Store the symbols of all units within a system
120 No_Symbols : constant Symbol_Array := (others => No_String);
122 -- The following record should be documented field by field
124 type System_Type is record
125 Type_Decl : Node_Id;
126 Unit_Names : Name_Array;
127 Unit_Symbols : Symbol_Array;
128 Dim_Symbols : Symbol_Array;
129 Count : Dimension_Position;
130 end record;
132 Null_System : constant System_Type :=
133 (Empty, No_Names, No_Symbols, No_Symbols, Invalid_Position);
135 subtype System_Id is Nat;
137 -- The following table maps types to systems
139 package System_Table is new Table.Table (
140 Table_Component_Type => System_Type,
141 Table_Index_Type => System_Id,
142 Table_Low_Bound => 1,
143 Table_Initial => 5,
144 Table_Increment => 5,
145 Table_Name => "System_Table");
147 --------------------
148 -- Dimension Type --
149 --------------------
151 type Dimension_Type is
152 array (Dimension_Position range
153 Low_Position_Bound .. High_Position_Bound) of Rational;
155 Null_Dimension : constant Dimension_Type := (others => Zero);
157 type Dimension_Table_Range is range 0 .. 510;
158 function Dimension_Table_Hash (Key : Node_Id) return Dimension_Table_Range;
160 -- The following table associates nodes with dimensions
162 package Dimension_Table is new
163 GNAT.HTable.Simple_HTable
164 (Header_Num => Dimension_Table_Range,
165 Element => Dimension_Type,
166 No_Element => Null_Dimension,
167 Key => Node_Id,
168 Hash => Dimension_Table_Hash,
169 Equal => "=");
171 ------------------
172 -- Symbol Types --
173 ------------------
175 type Symbol_Table_Range is range 0 .. 510;
176 function Symbol_Table_Hash (Key : Entity_Id) return Symbol_Table_Range;
178 -- Each subtype with a dimension has a symbolic representation of the
179 -- related unit. This table establishes a relation between the subtype
180 -- and the symbol.
182 package Symbol_Table is new
183 GNAT.HTable.Simple_HTable
184 (Header_Num => Symbol_Table_Range,
185 Element => String_Id,
186 No_Element => No_String,
187 Key => Entity_Id,
188 Hash => Symbol_Table_Hash,
189 Equal => "=");
191 -- The following array enumerates all contexts which may contain or
192 -- produce a dimension.
194 OK_For_Dimension : constant array (Node_Kind) of Boolean :=
195 (N_Attribute_Reference => True,
196 N_Expanded_Name => True,
197 N_Explicit_Dereference => True,
198 N_Defining_Identifier => True,
199 N_Function_Call => True,
200 N_Identifier => True,
201 N_Indexed_Component => True,
202 N_Integer_Literal => True,
203 N_Op_Abs => True,
204 N_Op_Add => True,
205 N_Op_Divide => True,
206 N_Op_Expon => True,
207 N_Op_Minus => True,
208 N_Op_Mod => True,
209 N_Op_Multiply => True,
210 N_Op_Plus => True,
211 N_Op_Rem => True,
212 N_Op_Subtract => True,
213 N_Qualified_Expression => True,
214 N_Real_Literal => True,
215 N_Selected_Component => True,
216 N_Slice => True,
217 N_Type_Conversion => True,
218 N_Unchecked_Type_Conversion => True,
220 others => False);
222 -----------------------
223 -- Local Subprograms --
224 -----------------------
226 procedure Analyze_Dimension_Assignment_Statement (N : Node_Id);
227 -- Subroutine of Analyze_Dimension for assignment statement. Check that the
228 -- dimensions of the left-hand side and the right-hand side of N match.
230 procedure Analyze_Dimension_Binary_Op (N : Node_Id);
231 -- Subroutine of Analyze_Dimension for binary operators. Check the
232 -- dimensions of the right and the left operand permit the operation.
233 -- Then, evaluate the resulting dimensions for each binary operator.
235 procedure Analyze_Dimension_Component_Declaration (N : Node_Id);
236 -- Subroutine of Analyze_Dimension for component declaration. Check that
237 -- the dimensions of the type of N and of the expression match.
239 procedure Analyze_Dimension_Extended_Return_Statement (N : Node_Id);
240 -- Subroutine of Analyze_Dimension for extended return statement. Check
241 -- that the dimensions of the returned type and of the returned object
242 -- match.
244 procedure Analyze_Dimension_Has_Etype (N : Node_Id);
245 -- Subroutine of Analyze_Dimension for a subset of N_Has_Etype denoted by
246 -- the list below:
247 -- N_Attribute_Reference
248 -- N_Identifier
249 -- N_Indexed_Component
250 -- N_Qualified_Expression
251 -- N_Selected_Component
252 -- N_Slice
253 -- N_Type_Conversion
254 -- N_Unchecked_Type_Conversion
256 procedure Analyze_Dimension_Number_Declaration (N : Node_Id);
257 -- Procedure to analyze dimension of expression in a number declaration.
258 -- This allows a named number to have nontrivial dimensions, while by
259 -- default a named number is dimensionless.
261 procedure Analyze_Dimension_Object_Declaration (N : Node_Id);
262 -- Subroutine of Analyze_Dimension for object declaration. Check that
263 -- the dimensions of the object type and the dimensions of the expression
264 -- (if expression is present) match. Note that when the expression is
265 -- a literal, no error is returned. This special case allows object
266 -- declaration such as: m : constant Length := 1.0;
268 procedure Analyze_Dimension_Object_Renaming_Declaration (N : Node_Id);
269 -- Subroutine of Analyze_Dimension for object renaming declaration. Check
270 -- the dimensions of the type and of the renamed object name of N match.
272 procedure Analyze_Dimension_Simple_Return_Statement (N : Node_Id);
273 -- Subroutine of Analyze_Dimension for simple return statement
274 -- Check that the dimensions of the returned type and of the returned
275 -- expression match.
277 procedure Analyze_Dimension_Subtype_Declaration (N : Node_Id);
278 -- Subroutine of Analyze_Dimension for subtype declaration. Propagate the
279 -- dimensions from the parent type to the identifier of N. Note that if
280 -- both the identifier and the parent type of N are not dimensionless,
281 -- return an error.
283 procedure Analyze_Dimension_Unary_Op (N : Node_Id);
284 -- Subroutine of Analyze_Dimension for unary operators. For Plus, Minus and
285 -- Abs operators, propagate the dimensions from the operand to N.
287 function Create_Rational_From
288 (Expr : Node_Id;
289 Complain : Boolean) return Rational;
290 -- Given an arbitrary expression Expr, return a valid rational if Expr can
291 -- be interpreted as a rational. Otherwise return No_Rational and also an
292 -- error message if Complain is set to True.
294 function Dimensions_Of (N : Node_Id) return Dimension_Type;
295 -- Return the dimension vector of node N
297 function Dimensions_Msg_Of
298 (N : Node_Id;
299 Description_Needed : Boolean := False) return String;
300 -- Given a node N, return the dimension symbols of N, preceded by "has
301 -- dimension" if Description_Needed. if N is dimensionless, return "'[']",
302 -- or "is dimensionless" if Description_Needed.
304 procedure Dim_Warning_For_Numeric_Literal (N : Node_Id; Typ : Entity_Id);
305 -- Issue a warning on the given numeric literal N to indicate that the
306 -- compiler made the assumption that the literal is not dimensionless
307 -- but has the dimension of Typ.
309 procedure Eval_Op_Expon_With_Rational_Exponent
310 (N : Node_Id;
311 Exponent_Value : Rational);
312 -- Evaluate the exponent it is a rational and the operand has a dimension
314 function Exists (Dim : Dimension_Type) return Boolean;
315 -- Returns True iff Dim does not denote the null dimension
317 function Exists (Str : String_Id) return Boolean;
318 -- Returns True iff Str does not denote No_String
320 function Exists (Sys : System_Type) return Boolean;
321 -- Returns True iff Sys does not denote the null system
323 function From_Dim_To_Str_Of_Dim_Symbols
324 (Dims : Dimension_Type;
325 System : System_Type;
326 In_Error_Msg : Boolean := False) return String_Id;
327 -- Given a dimension vector and a dimension system, return the proper
328 -- string of dimension symbols. If In_Error_Msg is True (i.e. the String_Id
329 -- will be used to issue an error message) then this routine has a special
330 -- handling for the insertion characters * or [ which must be preceded by
331 -- a quote ' to be placed literally into the message.
333 function From_Dim_To_Str_Of_Unit_Symbols
334 (Dims : Dimension_Type;
335 System : System_Type) return String_Id;
336 -- Given a dimension vector and a dimension system, return the proper
337 -- string of unit symbols.
339 function Is_Dim_IO_Package_Entity (E : Entity_Id) return Boolean;
340 -- Return True if E is the package entity of System.Dim.Float_IO or
341 -- System.Dim.Integer_IO.
343 function Is_Invalid (Position : Dimension_Position) return Boolean;
344 -- Return True if Pos denotes the invalid position
346 procedure Move_Dimensions (From : Node_Id; To : Node_Id);
347 -- Copy dimension vector of From to To and delete dimension vector of From
349 procedure Remove_Dimensions (N : Node_Id);
350 -- Remove the dimension vector of node N
352 procedure Set_Dimensions (N : Node_Id; Val : Dimension_Type);
353 -- Associate a dimension vector with a node
355 procedure Set_Symbol (E : Entity_Id; Val : String_Id);
356 -- Associate a symbol representation of a dimension vector with a subtype
358 function String_From_Numeric_Literal (N : Node_Id) return String_Id;
359 -- Return the string that corresponds to the numeric litteral N as it
360 -- appears in the source.
362 function Symbol_Of (E : Entity_Id) return String_Id;
363 -- E denotes a subtype with a dimension. Return the symbol representation
364 -- of the dimension vector.
366 function System_Of (E : Entity_Id) return System_Type;
367 -- E denotes a type, return associated system of the type if it has one
369 ---------
370 -- "+" --
371 ---------
373 function "+" (Right : Whole) return Rational is
374 begin
375 return Rational'(Numerator => Right, Denominator => 1);
376 end "+";
378 function "+" (Left, Right : Rational) return Rational is
379 R : constant Rational :=
380 Rational'(Numerator => Left.Numerator * Right.Denominator +
381 Left.Denominator * Right.Numerator,
382 Denominator => Left.Denominator * Right.Denominator);
383 begin
384 return Reduce (R);
385 end "+";
387 ---------
388 -- "-" --
389 ---------
391 function "-" (Right : Rational) return Rational is
392 begin
393 return Rational'(Numerator => -Right.Numerator,
394 Denominator => Right.Denominator);
395 end "-";
397 function "-" (Left, Right : Rational) return Rational is
398 R : constant Rational :=
399 Rational'(Numerator => Left.Numerator * Right.Denominator -
400 Left.Denominator * Right.Numerator,
401 Denominator => Left.Denominator * Right.Denominator);
403 begin
404 return Reduce (R);
405 end "-";
407 ---------
408 -- "*" --
409 ---------
411 function "*" (Left, Right : Rational) return Rational is
412 R : constant Rational :=
413 Rational'(Numerator => Left.Numerator * Right.Numerator,
414 Denominator => Left.Denominator * Right.Denominator);
415 begin
416 return Reduce (R);
417 end "*";
419 ---------
420 -- "/" --
421 ---------
423 function "/" (Left, Right : Rational) return Rational is
424 R : constant Rational := abs Right;
425 L : Rational := Left;
427 begin
428 if Right.Numerator < 0 then
429 L.Numerator := Whole (-Integer (L.Numerator));
430 end if;
432 return Reduce (Rational'(Numerator => L.Numerator * R.Denominator,
433 Denominator => L.Denominator * R.Numerator));
434 end "/";
436 -----------
437 -- "abs" --
438 -----------
440 function "abs" (Right : Rational) return Rational is
441 begin
442 return Rational'(Numerator => abs Right.Numerator,
443 Denominator => Right.Denominator);
444 end "abs";
446 ------------------------------
447 -- Analyze_Aspect_Dimension --
448 ------------------------------
450 -- with Dimension =>
451 -- ([Symbol =>] SYMBOL, DIMENSION_VALUE {, DIMENSION_Value})
453 -- SYMBOL ::= STRING_LITERAL | CHARACTER_LITERAL
455 -- DIMENSION_VALUE ::=
456 -- RATIONAL
457 -- | others => RATIONAL
458 -- | DISCRETE_CHOICE_LIST => RATIONAL
460 -- RATIONAL ::= [-] NUMERIC_LITERAL [/ NUMERIC_LITERAL]
462 -- Note that when the dimensioned type is an integer type, then any
463 -- dimension value must be an integer literal.
465 procedure Analyze_Aspect_Dimension
466 (N : Node_Id;
467 Id : Entity_Id;
468 Aggr : Node_Id)
470 Def_Id : constant Entity_Id := Defining_Identifier (N);
472 Processed : array (Dimension_Type'Range) of Boolean := (others => False);
473 -- This array is used when processing ranges or Others_Choice as part of
474 -- the dimension aggregate.
476 Dimensions : Dimension_Type := Null_Dimension;
478 procedure Extract_Power
479 (Expr : Node_Id;
480 Position : Dimension_Position);
481 -- Given an expression with denotes a rational number, read the number
482 -- and associate it with Position in Dimensions.
484 function Position_In_System
485 (Id : Node_Id;
486 System : System_Type) return Dimension_Position;
487 -- Given an identifier which denotes a dimension, return the position of
488 -- that dimension within System.
490 -------------------
491 -- Extract_Power --
492 -------------------
494 procedure Extract_Power
495 (Expr : Node_Id;
496 Position : Dimension_Position)
498 begin
499 -- Integer case
501 if Is_Integer_Type (Def_Id) then
503 -- Dimension value must be an integer literal
505 if Nkind (Expr) = N_Integer_Literal then
506 Dimensions (Position) := +Whole (UI_To_Int (Intval (Expr)));
507 else
508 Error_Msg_N ("integer literal expected", Expr);
509 end if;
511 -- Float case
513 else
514 Dimensions (Position) := Create_Rational_From (Expr, True);
515 end if;
517 Processed (Position) := True;
518 end Extract_Power;
520 ------------------------
521 -- Position_In_System --
522 ------------------------
524 function Position_In_System
525 (Id : Node_Id;
526 System : System_Type) return Dimension_Position
528 Dimension_Name : constant Name_Id := Chars (Id);
530 begin
531 for Position in System.Unit_Names'Range loop
532 if Dimension_Name = System.Unit_Names (Position) then
533 return Position;
534 end if;
535 end loop;
537 return Invalid_Position;
538 end Position_In_System;
540 -- Local variables
542 Assoc : Node_Id;
543 Choice : Node_Id;
544 Expr : Node_Id;
545 Num_Choices : Nat := 0;
546 Num_Dimensions : Nat := 0;
547 Others_Seen : Boolean := False;
548 Position : Nat := 0;
549 Sub_Ind : Node_Id;
550 Symbol : String_Id := No_String;
551 Symbol_Expr : Node_Id;
552 System : System_Type;
553 Typ : Entity_Id;
555 Errors_Count : Nat;
556 -- Errors_Count is a count of errors detected by the compiler so far
557 -- just before the extraction of symbol, names and values in the
558 -- aggregate (Step 2).
560 -- At the end of the analysis, there is a check to verify that this
561 -- count equals to Serious_Errors_Detected i.e. no erros have been
562 -- encountered during the process. Otherwise the Dimension_Table is
563 -- not filled.
565 -- Start of processing for Analyze_Aspect_Dimension
567 begin
568 -- STEP 1: Legality of aspect
570 if Nkind (N) /= N_Subtype_Declaration then
571 Error_Msg_NE ("aspect& must apply to subtype declaration", N, Id);
572 return;
573 end if;
575 Sub_Ind := Subtype_Indication (N);
576 Typ := Etype (Sub_Ind);
577 System := System_Of (Typ);
579 if Nkind (Sub_Ind) = N_Subtype_Indication then
580 Error_Msg_NE
581 ("constraint not allowed with aspect&", Constraint (Sub_Ind), Id);
582 return;
583 end if;
585 -- The dimension declarations are useless if the parent type does not
586 -- declare a valid system.
588 if not Exists (System) then
589 Error_Msg_NE
590 ("parent type of& lacks dimension system", Sub_Ind, Def_Id);
591 return;
592 end if;
594 if Nkind (Aggr) /= N_Aggregate then
595 Error_Msg_N ("aggregate expected", Aggr);
596 return;
597 end if;
599 -- STEP 2: Symbol, Names and values extraction
601 -- Get the number of errors detected by the compiler so far
603 Errors_Count := Serious_Errors_Detected;
605 -- STEP 2a: Symbol extraction
607 -- The first entry in the aggregate may be the symbolic representation
608 -- of the quantity.
610 -- Positional symbol argument
612 Symbol_Expr := First (Expressions (Aggr));
614 -- Named symbol argument
616 if No (Symbol_Expr)
617 or else not Nkind_In (Symbol_Expr, N_Character_Literal,
618 N_String_Literal)
619 then
620 Symbol_Expr := Empty;
622 -- Component associations present
624 if Present (Component_Associations (Aggr)) then
625 Assoc := First (Component_Associations (Aggr));
626 Choice := First (Choices (Assoc));
628 if No (Next (Choice)) and then Nkind (Choice) = N_Identifier then
630 -- Symbol component association is present
632 if Chars (Choice) = Name_Symbol then
633 Num_Choices := Num_Choices + 1;
634 Symbol_Expr := Expression (Assoc);
636 -- Verify symbol expression is a string or a character
638 if not Nkind_In (Symbol_Expr, N_Character_Literal,
639 N_String_Literal)
640 then
641 Symbol_Expr := Empty;
642 Error_Msg_N
643 ("symbol expression must be character or string",
644 Symbol_Expr);
645 end if;
647 -- Special error if no Symbol choice but expression is string
648 -- or character.
650 elsif Nkind_In (Expression (Assoc), N_Character_Literal,
651 N_String_Literal)
652 then
653 Num_Choices := Num_Choices + 1;
654 Error_Msg_N
655 ("optional component Symbol expected, found&", Choice);
656 end if;
657 end if;
658 end if;
659 end if;
661 -- STEP 2b: Names and values extraction
663 -- Positional elements
665 Expr := First (Expressions (Aggr));
667 -- Skip the symbol expression when present
669 if Present (Symbol_Expr) and then Num_Choices = 0 then
670 Expr := Next (Expr);
671 end if;
673 Position := Low_Position_Bound;
674 while Present (Expr) loop
675 if Position > High_Position_Bound then
676 Error_Msg_N
677 ("type& has more dimensions than system allows", Def_Id);
678 exit;
679 end if;
681 Extract_Power (Expr, Position);
683 Position := Position + 1;
684 Num_Dimensions := Num_Dimensions + 1;
686 Next (Expr);
687 end loop;
689 -- Named elements
691 Assoc := First (Component_Associations (Aggr));
693 -- Skip the symbol association when present
695 if Num_Choices = 1 then
696 Next (Assoc);
697 end if;
699 while Present (Assoc) loop
700 Expr := Expression (Assoc);
702 Choice := First (Choices (Assoc));
703 while Present (Choice) loop
705 -- Identifier case: NAME => EXPRESSION
707 if Nkind (Choice) = N_Identifier then
708 Position := Position_In_System (Choice, System);
710 if Is_Invalid (Position) then
711 Error_Msg_N ("dimension name& not part of system", Choice);
712 else
713 Extract_Power (Expr, Position);
714 end if;
716 -- Range case: NAME .. NAME => EXPRESSION
718 elsif Nkind (Choice) = N_Range then
719 declare
720 Low : constant Node_Id := Low_Bound (Choice);
721 High : constant Node_Id := High_Bound (Choice);
722 Low_Pos : Dimension_Position;
723 High_Pos : Dimension_Position;
725 begin
726 if Nkind (Low) /= N_Identifier then
727 Error_Msg_N ("bound must denote a dimension name", Low);
729 elsif Nkind (High) /= N_Identifier then
730 Error_Msg_N ("bound must denote a dimension name", High);
732 else
733 Low_Pos := Position_In_System (Low, System);
734 High_Pos := Position_In_System (High, System);
736 if Is_Invalid (Low_Pos) then
737 Error_Msg_N ("dimension name& not part of system",
738 Low);
740 elsif Is_Invalid (High_Pos) then
741 Error_Msg_N ("dimension name& not part of system",
742 High);
744 elsif Low_Pos > High_Pos then
745 Error_Msg_N ("expected low to high range", Choice);
747 else
748 for Position in Low_Pos .. High_Pos loop
749 Extract_Power (Expr, Position);
750 end loop;
751 end if;
752 end if;
753 end;
755 -- Others case: OTHERS => EXPRESSION
757 elsif Nkind (Choice) = N_Others_Choice then
758 if Present (Next (Choice)) or else Present (Prev (Choice)) then
759 Error_Msg_N
760 ("OTHERS must appear alone in a choice list", Choice);
762 elsif Present (Next (Assoc)) then
763 Error_Msg_N
764 ("OTHERS must appear last in an aggregate", Choice);
766 elsif Others_Seen then
767 Error_Msg_N ("multiple OTHERS not allowed", Choice);
769 else
770 -- Fill the non-processed dimensions with the default value
771 -- supplied by others.
773 for Position in Processed'Range loop
774 if not Processed (Position) then
775 Extract_Power (Expr, Position);
776 end if;
777 end loop;
778 end if;
780 Others_Seen := True;
782 -- All other cases are illegal declarations of dimension names
784 else
785 Error_Msg_NE ("wrong syntax for aspect&", Choice, Id);
786 end if;
788 Num_Choices := Num_Choices + 1;
789 Next (Choice);
790 end loop;
792 Num_Dimensions := Num_Dimensions + 1;
793 Next (Assoc);
794 end loop;
796 -- STEP 3: Consistency of system and dimensions
798 if Present (First (Expressions (Aggr)))
799 and then (First (Expressions (Aggr)) /= Symbol_Expr
800 or else Present (Next (Symbol_Expr)))
801 and then (Num_Choices > 1
802 or else (Num_Choices = 1 and then not Others_Seen))
803 then
804 Error_Msg_N
805 ("named associations cannot follow positional associations", Aggr);
806 end if;
808 if Num_Dimensions > System.Count then
809 Error_Msg_N ("type& has more dimensions than system allows", Def_Id);
811 elsif Num_Dimensions < System.Count and then not Others_Seen then
812 Error_Msg_N ("type& has less dimensions than system allows", Def_Id);
813 end if;
815 -- STEP 4: Dimension symbol extraction
817 if Present (Symbol_Expr) then
818 if Nkind (Symbol_Expr) = N_Character_Literal then
819 Start_String;
820 Store_String_Char (UI_To_CC (Char_Literal_Value (Symbol_Expr)));
821 Symbol := End_String;
823 else
824 Symbol := Strval (Symbol_Expr);
825 end if;
827 if String_Length (Symbol) = 0 then
828 Error_Msg_N ("empty string not allowed here", Symbol_Expr);
829 end if;
830 end if;
832 -- STEP 5: Storage of extracted values
834 -- Check that no errors have been detected during the analysis
836 if Errors_Count = Serious_Errors_Detected then
838 -- Check for useless declaration
840 if Symbol = No_String and then not Exists (Dimensions) then
841 Error_Msg_N ("useless dimension declaration", Aggr);
842 end if;
844 if Symbol /= No_String then
845 Set_Symbol (Def_Id, Symbol);
846 end if;
848 if Exists (Dimensions) then
849 Set_Dimensions (Def_Id, Dimensions);
850 end if;
851 end if;
852 end Analyze_Aspect_Dimension;
854 -------------------------------------
855 -- Analyze_Aspect_Dimension_System --
856 -------------------------------------
858 -- with Dimension_System => (DIMENSION {, DIMENSION});
860 -- DIMENSION ::= (
861 -- [Unit_Name =>] IDENTIFIER,
862 -- [Unit_Symbol =>] SYMBOL,
863 -- [Dim_Symbol =>] SYMBOL)
865 procedure Analyze_Aspect_Dimension_System
866 (N : Node_Id;
867 Id : Entity_Id;
868 Aggr : Node_Id)
870 function Is_Derived_Numeric_Type (N : Node_Id) return Boolean;
871 -- Determine whether type declaration N denotes a numeric derived type
873 -------------------------------
874 -- Is_Derived_Numeric_Type --
875 -------------------------------
877 function Is_Derived_Numeric_Type (N : Node_Id) return Boolean is
878 begin
879 return
880 Nkind (N) = N_Full_Type_Declaration
881 and then Nkind (Type_Definition (N)) = N_Derived_Type_Definition
882 and then Is_Numeric_Type
883 (Entity (Subtype_Indication (Type_Definition (N))));
884 end Is_Derived_Numeric_Type;
886 -- Local variables
888 Assoc : Node_Id;
889 Choice : Node_Id;
890 Dim_Aggr : Node_Id;
891 Dim_Symbol : Node_Id;
892 Dim_Symbols : Symbol_Array := No_Symbols;
893 Dim_System : System_Type := Null_System;
894 Position : Nat := 0;
895 Unit_Name : Node_Id;
896 Unit_Names : Name_Array := No_Names;
897 Unit_Symbol : Node_Id;
898 Unit_Symbols : Symbol_Array := No_Symbols;
900 Errors_Count : Nat;
901 -- Errors_Count is a count of errors detected by the compiler so far
902 -- just before the extraction of names and symbols in the aggregate
903 -- (Step 3).
905 -- At the end of the analysis, there is a check to verify that this
906 -- count equals Serious_Errors_Detected i.e. no errors have been
907 -- encountered during the process. Otherwise the System_Table is
908 -- not filled.
910 -- Start of processing for Analyze_Aspect_Dimension_System
912 begin
913 -- STEP 1: Legality of aspect
915 if not Is_Derived_Numeric_Type (N) then
916 Error_Msg_NE
917 ("aspect& must apply to numeric derived type declaration", N, Id);
918 return;
919 end if;
921 if Nkind (Aggr) /= N_Aggregate then
922 Error_Msg_N ("aggregate expected", Aggr);
923 return;
924 end if;
926 -- STEP 2: Structural verification of the dimension aggregate
928 if Present (Component_Associations (Aggr)) then
929 Error_Msg_N ("expected positional aggregate", Aggr);
930 return;
931 end if;
933 -- STEP 3: Name and Symbol extraction
935 Dim_Aggr := First (Expressions (Aggr));
936 Errors_Count := Serious_Errors_Detected;
937 while Present (Dim_Aggr) loop
938 Position := Position + 1;
940 if Position > High_Position_Bound then
941 Error_Msg_N ("too many dimensions in system", Aggr);
942 exit;
943 end if;
945 if Nkind (Dim_Aggr) /= N_Aggregate then
946 Error_Msg_N ("aggregate expected", Dim_Aggr);
948 else
949 if Present (Component_Associations (Dim_Aggr))
950 and then Present (Expressions (Dim_Aggr))
951 then
952 Error_Msg_N
953 ("mixed positional/named aggregate not allowed here",
954 Dim_Aggr);
956 -- Verify each dimension aggregate has three arguments
958 elsif List_Length (Component_Associations (Dim_Aggr)) /= 3
959 and then List_Length (Expressions (Dim_Aggr)) /= 3
960 then
961 Error_Msg_N
962 ("three components expected in aggregate", Dim_Aggr);
964 else
965 -- Named dimension aggregate
967 if Present (Component_Associations (Dim_Aggr)) then
969 -- Check first argument denotes the unit name
971 Assoc := First (Component_Associations (Dim_Aggr));
972 Choice := First (Choices (Assoc));
973 Unit_Name := Expression (Assoc);
975 if Present (Next (Choice))
976 or else Nkind (Choice) /= N_Identifier
977 then
978 Error_Msg_NE ("wrong syntax for aspect&", Choice, Id);
980 elsif Chars (Choice) /= Name_Unit_Name then
981 Error_Msg_N ("expected Unit_Name, found&", Choice);
982 end if;
984 -- Check the second argument denotes the unit symbol
986 Next (Assoc);
987 Choice := First (Choices (Assoc));
988 Unit_Symbol := Expression (Assoc);
990 if Present (Next (Choice))
991 or else Nkind (Choice) /= N_Identifier
992 then
993 Error_Msg_NE ("wrong syntax for aspect&", Choice, Id);
995 elsif Chars (Choice) /= Name_Unit_Symbol then
996 Error_Msg_N ("expected Unit_Symbol, found&", Choice);
997 end if;
999 -- Check the third argument denotes the dimension symbol
1001 Next (Assoc);
1002 Choice := First (Choices (Assoc));
1003 Dim_Symbol := Expression (Assoc);
1005 if Present (Next (Choice))
1006 or else Nkind (Choice) /= N_Identifier
1007 then
1008 Error_Msg_NE ("wrong syntax for aspect&", Choice, Id);
1009 elsif Chars (Choice) /= Name_Dim_Symbol then
1010 Error_Msg_N ("expected Dim_Symbol, found&", Choice);
1011 end if;
1013 -- Positional dimension aggregate
1015 else
1016 Unit_Name := First (Expressions (Dim_Aggr));
1017 Unit_Symbol := Next (Unit_Name);
1018 Dim_Symbol := Next (Unit_Symbol);
1019 end if;
1021 -- Check the first argument for each dimension aggregate is
1022 -- a name.
1024 if Nkind (Unit_Name) = N_Identifier then
1025 Unit_Names (Position) := Chars (Unit_Name);
1026 else
1027 Error_Msg_N ("expected unit name", Unit_Name);
1028 end if;
1030 -- Check the second argument for each dimension aggregate is
1031 -- a string or a character.
1033 if not Nkind_In (Unit_Symbol, N_String_Literal,
1034 N_Character_Literal)
1035 then
1036 Error_Msg_N
1037 ("expected unit symbol (string or character)",
1038 Unit_Symbol);
1040 else
1041 -- String case
1043 if Nkind (Unit_Symbol) = N_String_Literal then
1044 Unit_Symbols (Position) := Strval (Unit_Symbol);
1046 -- Character case
1048 else
1049 Start_String;
1050 Store_String_Char
1051 (UI_To_CC (Char_Literal_Value (Unit_Symbol)));
1052 Unit_Symbols (Position) := End_String;
1053 end if;
1055 -- Verify that the string is not empty
1057 if String_Length (Unit_Symbols (Position)) = 0 then
1058 Error_Msg_N
1059 ("empty string not allowed here", Unit_Symbol);
1060 end if;
1061 end if;
1063 -- Check the third argument for each dimension aggregate is
1064 -- a string or a character.
1066 if not Nkind_In (Dim_Symbol, N_String_Literal,
1067 N_Character_Literal)
1068 then
1069 Error_Msg_N
1070 ("expected dimension symbol (string or character)",
1071 Dim_Symbol);
1073 else
1074 -- String case
1076 if Nkind (Dim_Symbol) = N_String_Literal then
1077 Dim_Symbols (Position) := Strval (Dim_Symbol);
1079 -- Character case
1081 else
1082 Start_String;
1083 Store_String_Char
1084 (UI_To_CC (Char_Literal_Value (Dim_Symbol)));
1085 Dim_Symbols (Position) := End_String;
1086 end if;
1088 -- Verify that the string is not empty
1090 if String_Length (Dim_Symbols (Position)) = 0 then
1091 Error_Msg_N ("empty string not allowed here", Dim_Symbol);
1092 end if;
1093 end if;
1094 end if;
1095 end if;
1097 Next (Dim_Aggr);
1098 end loop;
1100 -- STEP 4: Storage of extracted values
1102 -- Check that no errors have been detected during the analysis
1104 if Errors_Count = Serious_Errors_Detected then
1105 Dim_System.Type_Decl := N;
1106 Dim_System.Unit_Names := Unit_Names;
1107 Dim_System.Unit_Symbols := Unit_Symbols;
1108 Dim_System.Dim_Symbols := Dim_Symbols;
1109 Dim_System.Count := Position;
1110 System_Table.Append (Dim_System);
1111 end if;
1112 end Analyze_Aspect_Dimension_System;
1114 -----------------------
1115 -- Analyze_Dimension --
1116 -----------------------
1118 -- This dispatch routine propagates dimensions for each node
1120 procedure Analyze_Dimension (N : Node_Id) is
1121 begin
1122 -- Aspect is an Ada 2012 feature. Note that there is no need to check
1123 -- dimensions for nodes that don't come from source, except for subtype
1124 -- declarations where the dimensions are inherited from the base type,
1125 -- and for explicit dereferences generated when expanding iterators.
1127 if Ada_Version < Ada_2012 then
1128 return;
1130 elsif not Comes_From_Source (N)
1131 and then Nkind (N) /= N_Subtype_Declaration
1132 and then Nkind (N) /= N_Explicit_Dereference
1133 then
1134 return;
1135 end if;
1137 case Nkind (N) is
1138 when N_Assignment_Statement =>
1139 Analyze_Dimension_Assignment_Statement (N);
1141 when N_Binary_Op =>
1142 Analyze_Dimension_Binary_Op (N);
1144 when N_Component_Declaration =>
1145 Analyze_Dimension_Component_Declaration (N);
1147 when N_Extended_Return_Statement =>
1148 Analyze_Dimension_Extended_Return_Statement (N);
1150 when N_Attribute_Reference |
1151 N_Expanded_Name |
1152 N_Explicit_Dereference |
1153 N_Function_Call |
1154 N_Indexed_Component |
1155 N_Qualified_Expression |
1156 N_Selected_Component |
1157 N_Slice |
1158 N_Type_Conversion |
1159 N_Unchecked_Type_Conversion =>
1160 Analyze_Dimension_Has_Etype (N);
1162 -- In the presence of a repaired syntax error, an identifier
1163 -- may be introduced without a usable type.
1165 when N_Identifier =>
1166 if Present (Etype (N)) then
1167 Analyze_Dimension_Has_Etype (N);
1168 end if;
1170 when N_Number_Declaration =>
1171 Analyze_Dimension_Number_Declaration (N);
1173 when N_Object_Declaration =>
1174 Analyze_Dimension_Object_Declaration (N);
1176 when N_Object_Renaming_Declaration =>
1177 Analyze_Dimension_Object_Renaming_Declaration (N);
1179 when N_Simple_Return_Statement =>
1180 if not Comes_From_Extended_Return_Statement (N) then
1181 Analyze_Dimension_Simple_Return_Statement (N);
1182 end if;
1184 when N_Subtype_Declaration =>
1185 Analyze_Dimension_Subtype_Declaration (N);
1187 when N_Unary_Op =>
1188 Analyze_Dimension_Unary_Op (N);
1190 when others => null;
1192 end case;
1193 end Analyze_Dimension;
1195 ---------------------------------------
1196 -- Analyze_Dimension_Array_Aggregate --
1197 ---------------------------------------
1199 procedure Analyze_Dimension_Array_Aggregate
1200 (N : Node_Id;
1201 Comp_Typ : Entity_Id)
1203 Comp_Ass : constant List_Id := Component_Associations (N);
1204 Dims_Of_Comp_Typ : constant Dimension_Type := Dimensions_Of (Comp_Typ);
1205 Exps : constant List_Id := Expressions (N);
1207 Comp : Node_Id;
1208 Expr : Node_Id;
1210 Error_Detected : Boolean := False;
1211 -- This flag is used in order to indicate if an error has been detected
1212 -- so far by the compiler in this routine.
1214 begin
1215 -- Aspect is an Ada 2012 feature. Nothing to do here if the component
1216 -- base type is not a dimensioned type.
1218 -- Note that here the original node must come from source since the
1219 -- original array aggregate may not have been entirely decorated.
1221 if Ada_Version < Ada_2012
1222 or else not Comes_From_Source (Original_Node (N))
1223 or else not Has_Dimension_System (Base_Type (Comp_Typ))
1224 then
1225 return;
1226 end if;
1228 -- Check whether there is any positional component association
1230 if Is_Empty_List (Exps) then
1231 Comp := First (Comp_Ass);
1232 else
1233 Comp := First (Exps);
1234 end if;
1236 while Present (Comp) loop
1238 -- Get the expression from the component
1240 if Nkind (Comp) = N_Component_Association then
1241 Expr := Expression (Comp);
1242 else
1243 Expr := Comp;
1244 end if;
1246 -- Issue an error if the dimensions of the component type and the
1247 -- dimensions of the component mismatch.
1249 -- Note that we must ensure the expression has been fully analyzed
1250 -- since it may not be decorated at this point. We also don't want to
1251 -- issue the same error message multiple times on the same expression
1252 -- (may happen when an aggregate is converted into a positional
1253 -- aggregate). We also must verify that this is a scalar component,
1254 -- and not a subaggregate of a multidimensional aggregate.
1256 if Comes_From_Source (Original_Node (Expr))
1257 and then Present (Etype (Expr))
1258 and then Is_Numeric_Type (Etype (Expr))
1259 and then Dimensions_Of (Expr) /= Dims_Of_Comp_Typ
1260 and then Sloc (Comp) /= Sloc (Prev (Comp))
1261 then
1262 -- Check if an error has already been encountered so far
1264 if not Error_Detected then
1265 Error_Msg_N ("dimensions mismatch in array aggregate", N);
1266 Error_Detected := True;
1267 end if;
1269 Error_Msg_N
1270 ("\expected dimension " & Dimensions_Msg_Of (Comp_Typ)
1271 & ", found " & Dimensions_Msg_Of (Expr), Expr);
1272 end if;
1274 -- Look at the named components right after the positional components
1276 if not Present (Next (Comp))
1277 and then List_Containing (Comp) = Exps
1278 then
1279 Comp := First (Comp_Ass);
1280 else
1281 Next (Comp);
1282 end if;
1283 end loop;
1284 end Analyze_Dimension_Array_Aggregate;
1286 --------------------------------------------
1287 -- Analyze_Dimension_Assignment_Statement --
1288 --------------------------------------------
1290 procedure Analyze_Dimension_Assignment_Statement (N : Node_Id) is
1291 Lhs : constant Node_Id := Name (N);
1292 Dims_Of_Lhs : constant Dimension_Type := Dimensions_Of (Lhs);
1293 Rhs : constant Node_Id := Expression (N);
1294 Dims_Of_Rhs : constant Dimension_Type := Dimensions_Of (Rhs);
1296 procedure Error_Dim_Msg_For_Assignment_Statement
1297 (N : Node_Id;
1298 Lhs : Node_Id;
1299 Rhs : Node_Id);
1300 -- Error using Error_Msg_N at node N. Output the dimensions of left
1301 -- and right hand sides.
1303 --------------------------------------------
1304 -- Error_Dim_Msg_For_Assignment_Statement --
1305 --------------------------------------------
1307 procedure Error_Dim_Msg_For_Assignment_Statement
1308 (N : Node_Id;
1309 Lhs : Node_Id;
1310 Rhs : Node_Id)
1312 begin
1313 Error_Msg_N ("dimensions mismatch in assignment", N);
1314 Error_Msg_N ("\left-hand side " & Dimensions_Msg_Of (Lhs, True), N);
1315 Error_Msg_N ("\right-hand side " & Dimensions_Msg_Of (Rhs, True), N);
1316 end Error_Dim_Msg_For_Assignment_Statement;
1318 -- Start of processing for Analyze_Dimension_Assignment
1320 begin
1321 if Dims_Of_Lhs /= Dims_Of_Rhs then
1322 Error_Dim_Msg_For_Assignment_Statement (N, Lhs, Rhs);
1323 end if;
1324 end Analyze_Dimension_Assignment_Statement;
1326 ---------------------------------
1327 -- Analyze_Dimension_Binary_Op --
1328 ---------------------------------
1330 -- Check and propagate the dimensions for binary operators
1331 -- Note that when the dimensions mismatch, no dimension is propagated to N.
1333 procedure Analyze_Dimension_Binary_Op (N : Node_Id) is
1334 N_Kind : constant Node_Kind := Nkind (N);
1336 function Dimensions_Of_Operand (N : Node_Id) return Dimension_Type;
1337 -- If the operand is a numeric literal that comes from a declared
1338 -- constant, use the dimensions of the constant which were computed
1339 -- from the expression of the constant declaration.
1341 procedure Error_Dim_Msg_For_Binary_Op (N, L, R : Node_Id);
1342 -- Error using Error_Msg_NE and Error_Msg_N at node N. Output the
1343 -- dimensions of both operands.
1345 ---------------------------
1346 -- Dimensions_Of_Operand --
1347 ---------------------------
1349 function Dimensions_Of_Operand (N : Node_Id) return Dimension_Type is
1350 begin
1351 if Nkind (N) = N_Real_Literal
1352 and then Present (Original_Entity (N))
1353 then
1354 return Dimensions_Of (Original_Entity (N));
1355 else
1356 return Dimensions_Of (N);
1357 end if;
1358 end Dimensions_Of_Operand;
1360 ---------------------------------
1361 -- Error_Dim_Msg_For_Binary_Op --
1362 ---------------------------------
1364 procedure Error_Dim_Msg_For_Binary_Op (N, L, R : Node_Id) is
1365 begin
1366 Error_Msg_NE
1367 ("both operands for operation& must have same dimensions",
1368 N, Entity (N));
1369 Error_Msg_N ("\left operand " & Dimensions_Msg_Of (L, True), N);
1370 Error_Msg_N ("\right operand " & Dimensions_Msg_Of (R, True), N);
1371 end Error_Dim_Msg_For_Binary_Op;
1373 -- Start of processing for Analyze_Dimension_Binary_Op
1375 begin
1376 if Nkind_In (N_Kind, N_Op_Add, N_Op_Expon, N_Op_Subtract)
1377 or else N_Kind in N_Multiplying_Operator
1378 or else N_Kind in N_Op_Compare
1379 then
1380 declare
1381 L : constant Node_Id := Left_Opnd (N);
1382 Dims_Of_L : constant Dimension_Type :=
1383 Dimensions_Of_Operand (L);
1384 L_Has_Dimensions : constant Boolean := Exists (Dims_Of_L);
1385 R : constant Node_Id := Right_Opnd (N);
1386 Dims_Of_R : constant Dimension_Type :=
1387 Dimensions_Of_Operand (R);
1388 R_Has_Dimensions : constant Boolean := Exists (Dims_Of_R);
1389 Dims_Of_N : Dimension_Type := Null_Dimension;
1391 begin
1392 -- N_Op_Add, N_Op_Mod, N_Op_Rem or N_Op_Subtract case
1394 if Nkind_In (N, N_Op_Add, N_Op_Mod, N_Op_Rem, N_Op_Subtract) then
1396 -- Check both operands have same dimension
1398 if Dims_Of_L /= Dims_Of_R then
1399 Error_Dim_Msg_For_Binary_Op (N, L, R);
1400 else
1401 -- Check both operands are not dimensionless
1403 if Exists (Dims_Of_L) then
1404 Set_Dimensions (N, Dims_Of_L);
1405 end if;
1406 end if;
1408 -- N_Op_Multiply or N_Op_Divide case
1410 elsif Nkind_In (N_Kind, N_Op_Multiply, N_Op_Divide) then
1412 -- Check at least one operand is not dimensionless
1414 if L_Has_Dimensions or R_Has_Dimensions then
1416 -- Multiplication case
1418 -- Get both operands dimensions and add them
1420 if N_Kind = N_Op_Multiply then
1421 for Position in Dimension_Type'Range loop
1422 Dims_Of_N (Position) :=
1423 Dims_Of_L (Position) + Dims_Of_R (Position);
1424 end loop;
1426 -- Division case
1428 -- Get both operands dimensions and subtract them
1430 else
1431 for Position in Dimension_Type'Range loop
1432 Dims_Of_N (Position) :=
1433 Dims_Of_L (Position) - Dims_Of_R (Position);
1434 end loop;
1435 end if;
1437 if Exists (Dims_Of_N) then
1438 Set_Dimensions (N, Dims_Of_N);
1439 end if;
1440 end if;
1442 -- Exponentiation case
1444 -- Note: a rational exponent is allowed for dimensioned operand
1446 elsif N_Kind = N_Op_Expon then
1448 -- Check the left operand is not dimensionless. Note that the
1449 -- value of the exponent must be known compile time. Otherwise,
1450 -- the exponentiation evaluation will return an error message.
1452 if L_Has_Dimensions then
1453 if not Compile_Time_Known_Value (R) then
1454 Error_Msg_N
1455 ("exponent of dimensioned operand must be "
1456 & "known at compile time", N);
1457 end if;
1459 declare
1460 Exponent_Value : Rational := Zero;
1462 begin
1463 -- Real operand case
1465 if Is_Real_Type (Etype (L)) then
1467 -- Define the exponent as a Rational number
1469 Exponent_Value := Create_Rational_From (R, False);
1471 -- Verify that the exponent cannot be interpreted
1472 -- as a rational, otherwise interpret the exponent
1473 -- as an integer.
1475 if Exponent_Value = No_Rational then
1476 Exponent_Value :=
1477 +Whole (UI_To_Int (Expr_Value (R)));
1478 end if;
1480 -- Integer operand case.
1482 -- For integer operand, the exponent cannot be
1483 -- interpreted as a rational.
1485 else
1486 Exponent_Value := +Whole (UI_To_Int (Expr_Value (R)));
1487 end if;
1489 for Position in Dimension_Type'Range loop
1490 Dims_Of_N (Position) :=
1491 Dims_Of_L (Position) * Exponent_Value;
1492 end loop;
1494 if Exists (Dims_Of_N) then
1495 Set_Dimensions (N, Dims_Of_N);
1496 end if;
1497 end;
1498 end if;
1500 -- Comparison cases
1502 -- For relational operations, only dimension checking is
1503 -- performed (no propagation). If one operand is the result
1504 -- of constant folding the dimensions may have been lost
1505 -- in a tree copy, so assume that pre-analysis has verified
1506 -- that dimensions are correct.
1508 elsif N_Kind in N_Op_Compare then
1509 if (L_Has_Dimensions or R_Has_Dimensions)
1510 and then Dims_Of_L /= Dims_Of_R
1511 then
1512 if Nkind (L) = N_Real_Literal
1513 and then not (Comes_From_Source (L))
1514 and then Expander_Active
1515 then
1516 null;
1518 elsif Nkind (R) = N_Real_Literal
1519 and then not (Comes_From_Source (R))
1520 and then Expander_Active
1521 then
1522 null;
1524 else
1525 Error_Dim_Msg_For_Binary_Op (N, L, R);
1526 end if;
1527 end if;
1528 end if;
1530 -- If expander is active, remove dimension information from each
1531 -- operand, as only dimensions of result are relevant.
1533 if Expander_Active then
1534 Remove_Dimensions (L);
1535 Remove_Dimensions (R);
1536 end if;
1537 end;
1538 end if;
1539 end Analyze_Dimension_Binary_Op;
1541 ----------------------------
1542 -- Analyze_Dimension_Call --
1543 ----------------------------
1545 procedure Analyze_Dimension_Call (N : Node_Id; Nam : Entity_Id) is
1546 Actuals : constant List_Id := Parameter_Associations (N);
1547 Actual : Node_Id;
1548 Dims_Of_Formal : Dimension_Type;
1549 Formal : Node_Id;
1550 Formal_Typ : Entity_Id;
1552 Error_Detected : Boolean := False;
1553 -- This flag is used in order to indicate if an error has been detected
1554 -- so far by the compiler in this routine.
1556 begin
1557 -- Aspect is an Ada 2012 feature. Note that there is no need to check
1558 -- dimensions for calls that don't come from source, or those that may
1559 -- have semantic errors.
1561 if Ada_Version < Ada_2012
1562 or else not Comes_From_Source (N)
1563 or else Error_Posted (N)
1564 then
1565 return;
1566 end if;
1568 -- Check the dimensions of the actuals, if any
1570 if not Is_Empty_List (Actuals) then
1572 -- Special processing for elementary functions
1574 -- For Sqrt call, the resulting dimensions equal to half the
1575 -- dimensions of the actual. For all other elementary calls, this
1576 -- routine check that every actual is dimensionless.
1578 if Nkind (N) = N_Function_Call then
1579 Elementary_Function_Calls : declare
1580 Dims_Of_Call : Dimension_Type;
1581 Ent : Entity_Id := Nam;
1583 function Is_Elementary_Function_Entity
1584 (Sub_Id : Entity_Id) return Boolean;
1585 -- Given Sub_Id, the original subprogram entity, return True
1586 -- if call is to an elementary function (see Ada.Numerics.
1587 -- Generic_Elementary_Functions).
1589 -----------------------------------
1590 -- Is_Elementary_Function_Entity --
1591 -----------------------------------
1593 function Is_Elementary_Function_Entity
1594 (Sub_Id : Entity_Id) return Boolean
1596 Loc : constant Source_Ptr := Sloc (Sub_Id);
1598 begin
1599 -- Is entity in Ada.Numerics.Generic_Elementary_Functions?
1601 return
1602 Loc > No_Location
1603 and then
1604 Is_RTU
1605 (Cunit_Entity (Get_Source_Unit (Loc)),
1606 Ada_Numerics_Generic_Elementary_Functions);
1607 end Is_Elementary_Function_Entity;
1609 -- Start of processing for Elementary_Function_Calls
1611 begin
1612 -- Get original subprogram entity following the renaming chain
1614 if Present (Alias (Ent)) then
1615 Ent := Alias (Ent);
1616 end if;
1618 -- Check the call is an Elementary function call
1620 if Is_Elementary_Function_Entity (Ent) then
1622 -- Sqrt function call case
1624 if Chars (Ent) = Name_Sqrt then
1625 Dims_Of_Call := Dimensions_Of (First_Actual (N));
1627 -- Evaluates the resulting dimensions (i.e. half the
1628 -- dimensions of the actual).
1630 if Exists (Dims_Of_Call) then
1631 for Position in Dims_Of_Call'Range loop
1632 Dims_Of_Call (Position) :=
1633 Dims_Of_Call (Position) *
1634 Rational'(Numerator => 1, Denominator => 2);
1635 end loop;
1637 Set_Dimensions (N, Dims_Of_Call);
1638 end if;
1640 -- All other elementary functions case. Note that every
1641 -- actual here should be dimensionless.
1643 else
1644 Actual := First_Actual (N);
1645 while Present (Actual) loop
1646 if Exists (Dimensions_Of (Actual)) then
1648 -- Check if error has already been encountered
1650 if not Error_Detected then
1651 Error_Msg_NE
1652 ("dimensions mismatch in call of&",
1653 N, Name (N));
1654 Error_Detected := True;
1655 end if;
1657 Error_Msg_N
1658 ("\expected dimension '['], found "
1659 & Dimensions_Msg_Of (Actual), Actual);
1660 end if;
1662 Next_Actual (Actual);
1663 end loop;
1664 end if;
1666 -- Nothing more to do for elementary functions
1668 return;
1669 end if;
1670 end Elementary_Function_Calls;
1671 end if;
1673 -- General case. Check, for each parameter, the dimensions of the
1674 -- actual and its corresponding formal match. Otherwise, complain.
1676 Actual := First_Actual (N);
1677 Formal := First_Formal (Nam);
1678 while Present (Formal) loop
1680 -- A missing corresponding actual indicates that the analysis of
1681 -- the call was aborted due to a previous error.
1683 if No (Actual) then
1684 Check_Error_Detected;
1685 return;
1686 end if;
1688 Formal_Typ := Etype (Formal);
1689 Dims_Of_Formal := Dimensions_Of (Formal_Typ);
1691 -- If the formal is not dimensionless, check dimensions of formal
1692 -- and actual match. Otherwise, complain.
1694 if Exists (Dims_Of_Formal)
1695 and then Dimensions_Of (Actual) /= Dims_Of_Formal
1696 then
1697 -- Check if an error has already been encountered so far
1699 if not Error_Detected then
1700 Error_Msg_NE ("dimensions mismatch in& call", N, Name (N));
1701 Error_Detected := True;
1702 end if;
1704 Error_Msg_N
1705 ("\expected dimension " & Dimensions_Msg_Of (Formal_Typ)
1706 & ", found " & Dimensions_Msg_Of (Actual), Actual);
1707 end if;
1709 Next_Actual (Actual);
1710 Next_Formal (Formal);
1711 end loop;
1712 end if;
1714 -- For function calls, propagate the dimensions from the returned type
1716 if Nkind (N) = N_Function_Call then
1717 Analyze_Dimension_Has_Etype (N);
1718 end if;
1719 end Analyze_Dimension_Call;
1721 ---------------------------------------------
1722 -- Analyze_Dimension_Component_Declaration --
1723 ---------------------------------------------
1725 procedure Analyze_Dimension_Component_Declaration (N : Node_Id) is
1726 Expr : constant Node_Id := Expression (N);
1727 Id : constant Entity_Id := Defining_Identifier (N);
1728 Etyp : constant Entity_Id := Etype (Id);
1729 Dims_Of_Etyp : constant Dimension_Type := Dimensions_Of (Etyp);
1730 Dims_Of_Expr : Dimension_Type;
1732 procedure Error_Dim_Msg_For_Component_Declaration
1733 (N : Node_Id;
1734 Etyp : Entity_Id;
1735 Expr : Node_Id);
1736 -- Error using Error_Msg_N at node N. Output the dimensions of the
1737 -- type Etyp and the expression Expr of N.
1739 ---------------------------------------------
1740 -- Error_Dim_Msg_For_Component_Declaration --
1741 ---------------------------------------------
1743 procedure Error_Dim_Msg_For_Component_Declaration
1744 (N : Node_Id;
1745 Etyp : Entity_Id;
1746 Expr : Node_Id) is
1747 begin
1748 Error_Msg_N ("dimensions mismatch in component declaration", N);
1749 Error_Msg_N
1750 ("\expected dimension " & Dimensions_Msg_Of (Etyp) & ", found "
1751 & Dimensions_Msg_Of (Expr), Expr);
1752 end Error_Dim_Msg_For_Component_Declaration;
1754 -- Start of processing for Analyze_Dimension_Component_Declaration
1756 begin
1757 -- Expression is present
1759 if Present (Expr) then
1760 Dims_Of_Expr := Dimensions_Of (Expr);
1762 -- Check dimensions match
1764 if Dims_Of_Etyp /= Dims_Of_Expr then
1766 -- Numeric literal case. Issue a warning if the object type is not
1767 -- dimensionless to indicate the literal is treated as if its
1768 -- dimension matches the type dimension.
1770 if Nkind_In (Original_Node (Expr), N_Real_Literal,
1771 N_Integer_Literal)
1772 then
1773 Dim_Warning_For_Numeric_Literal (Expr, Etyp);
1775 -- Issue a dimension mismatch error for all other cases
1777 else
1778 Error_Dim_Msg_For_Component_Declaration (N, Etyp, Expr);
1779 end if;
1780 end if;
1781 end if;
1782 end Analyze_Dimension_Component_Declaration;
1784 -------------------------------------------------
1785 -- Analyze_Dimension_Extended_Return_Statement --
1786 -------------------------------------------------
1788 procedure Analyze_Dimension_Extended_Return_Statement (N : Node_Id) is
1789 Return_Ent : constant Entity_Id := Return_Statement_Entity (N);
1790 Return_Etyp : constant Entity_Id :=
1791 Etype (Return_Applies_To (Return_Ent));
1792 Return_Obj_Decls : constant List_Id := Return_Object_Declarations (N);
1793 Return_Obj_Decl : Node_Id;
1794 Return_Obj_Id : Entity_Id;
1795 Return_Obj_Typ : Entity_Id;
1797 procedure Error_Dim_Msg_For_Extended_Return_Statement
1798 (N : Node_Id;
1799 Return_Etyp : Entity_Id;
1800 Return_Obj_Typ : Entity_Id);
1801 -- Error using Error_Msg_N at node N. Output dimensions of the returned
1802 -- type Return_Etyp and the returned object type Return_Obj_Typ of N.
1804 -------------------------------------------------
1805 -- Error_Dim_Msg_For_Extended_Return_Statement --
1806 -------------------------------------------------
1808 procedure Error_Dim_Msg_For_Extended_Return_Statement
1809 (N : Node_Id;
1810 Return_Etyp : Entity_Id;
1811 Return_Obj_Typ : Entity_Id)
1813 begin
1814 Error_Msg_N ("dimensions mismatch in extended return statement", N);
1815 Error_Msg_N
1816 ("\expected dimension " & Dimensions_Msg_Of (Return_Etyp)
1817 & ", found " & Dimensions_Msg_Of (Return_Obj_Typ), N);
1818 end Error_Dim_Msg_For_Extended_Return_Statement;
1820 -- Start of processing for Analyze_Dimension_Extended_Return_Statement
1822 begin
1823 if Present (Return_Obj_Decls) then
1824 Return_Obj_Decl := First (Return_Obj_Decls);
1825 while Present (Return_Obj_Decl) loop
1826 if Nkind (Return_Obj_Decl) = N_Object_Declaration then
1827 Return_Obj_Id := Defining_Identifier (Return_Obj_Decl);
1829 if Is_Return_Object (Return_Obj_Id) then
1830 Return_Obj_Typ := Etype (Return_Obj_Id);
1832 -- Issue an error message if dimensions mismatch
1834 if Dimensions_Of (Return_Etyp) /=
1835 Dimensions_Of (Return_Obj_Typ)
1836 then
1837 Error_Dim_Msg_For_Extended_Return_Statement
1838 (N, Return_Etyp, Return_Obj_Typ);
1839 return;
1840 end if;
1841 end if;
1842 end if;
1844 Next (Return_Obj_Decl);
1845 end loop;
1846 end if;
1847 end Analyze_Dimension_Extended_Return_Statement;
1849 -----------------------------------------------------
1850 -- Analyze_Dimension_Extension_Or_Record_Aggregate --
1851 -----------------------------------------------------
1853 procedure Analyze_Dimension_Extension_Or_Record_Aggregate (N : Node_Id) is
1854 Comp : Node_Id;
1855 Comp_Id : Entity_Id;
1856 Comp_Typ : Entity_Id;
1857 Expr : Node_Id;
1859 Error_Detected : Boolean := False;
1860 -- This flag is used in order to indicate if an error has been detected
1861 -- so far by the compiler in this routine.
1863 begin
1864 -- Aspect is an Ada 2012 feature. Note that there is no need to check
1865 -- dimensions for aggregates that don't come from source, or if we are
1866 -- within an initialization procedure, whose expressions have been
1867 -- checked at the point of record declaration.
1869 if Ada_Version < Ada_2012
1870 or else not Comes_From_Source (N)
1871 or else Inside_Init_Proc
1872 then
1873 return;
1874 end if;
1876 Comp := First (Component_Associations (N));
1877 while Present (Comp) loop
1878 Comp_Id := Entity (First (Choices (Comp)));
1879 Comp_Typ := Etype (Comp_Id);
1881 -- Check the component type is either a dimensioned type or a
1882 -- dimensioned subtype.
1884 if Has_Dimension_System (Base_Type (Comp_Typ)) then
1885 Expr := Expression (Comp);
1887 -- A box-initialized component needs no checking.
1889 if No (Expr) and then Box_Present (Comp) then
1890 null;
1892 -- Issue an error if the dimensions of the component type and the
1893 -- dimensions of the component mismatch.
1895 elsif Dimensions_Of (Expr) /= Dimensions_Of (Comp_Typ) then
1897 -- Check if an error has already been encountered so far
1899 if not Error_Detected then
1901 -- Extension aggregate case
1903 if Nkind (N) = N_Extension_Aggregate then
1904 Error_Msg_N
1905 ("dimensions mismatch in extension aggregate", N);
1907 -- Record aggregate case
1909 else
1910 Error_Msg_N
1911 ("dimensions mismatch in record aggregate", N);
1912 end if;
1914 Error_Detected := True;
1915 end if;
1917 Error_Msg_N
1918 ("\expected dimension " & Dimensions_Msg_Of (Comp_Typ)
1919 & ", found " & Dimensions_Msg_Of (Expr), Comp);
1920 end if;
1921 end if;
1923 Next (Comp);
1924 end loop;
1925 end Analyze_Dimension_Extension_Or_Record_Aggregate;
1927 -------------------------------
1928 -- Analyze_Dimension_Formals --
1929 -------------------------------
1931 procedure Analyze_Dimension_Formals (N : Node_Id; Formals : List_Id) is
1932 Dims_Of_Typ : Dimension_Type;
1933 Formal : Node_Id;
1934 Typ : Entity_Id;
1936 begin
1937 -- Aspect is an Ada 2012 feature. Note that there is no need to check
1938 -- dimensions for sub specs that don't come from source.
1940 if Ada_Version < Ada_2012 or else not Comes_From_Source (N) then
1941 return;
1942 end if;
1944 Formal := First (Formals);
1945 while Present (Formal) loop
1946 Typ := Parameter_Type (Formal);
1947 Dims_Of_Typ := Dimensions_Of (Typ);
1949 if Exists (Dims_Of_Typ) then
1950 declare
1951 Expr : constant Node_Id := Expression (Formal);
1953 begin
1954 -- Issue a warning if Expr is a numeric literal and if its
1955 -- dimensions differ with the dimensions of the formal type.
1957 if Present (Expr)
1958 and then Dims_Of_Typ /= Dimensions_Of (Expr)
1959 and then Nkind_In (Original_Node (Expr), N_Real_Literal,
1960 N_Integer_Literal)
1961 then
1962 Dim_Warning_For_Numeric_Literal (Expr, Etype (Typ));
1963 end if;
1964 end;
1965 end if;
1967 Next (Formal);
1968 end loop;
1969 end Analyze_Dimension_Formals;
1971 ---------------------------------
1972 -- Analyze_Dimension_Has_Etype --
1973 ---------------------------------
1975 procedure Analyze_Dimension_Has_Etype (N : Node_Id) is
1976 Etyp : constant Entity_Id := Etype (N);
1977 Dims_Of_Etyp : Dimension_Type := Dimensions_Of (Etyp);
1979 begin
1980 -- General case. Propagation of the dimensions from the type
1982 if Exists (Dims_Of_Etyp) then
1983 Set_Dimensions (N, Dims_Of_Etyp);
1985 -- Identifier case. Propagate the dimensions from the entity for
1986 -- identifier whose entity is a non-dimensionless constant.
1988 elsif Nkind (N) = N_Identifier then
1989 Analyze_Dimension_Identifier : declare
1990 Id : constant Entity_Id := Entity (N);
1992 begin
1993 -- If Id is missing, abnormal tree, assume previous error
1995 if No (Id) then
1996 Check_Error_Detected;
1997 return;
1999 elsif Ekind_In (Id, E_Constant, E_Named_Real)
2000 and then Exists (Dimensions_Of (Id))
2001 then
2002 Set_Dimensions (N, Dimensions_Of (Id));
2003 end if;
2004 end Analyze_Dimension_Identifier;
2006 -- Attribute reference case. Propagate the dimensions from the prefix.
2008 elsif Nkind (N) = N_Attribute_Reference
2009 and then Has_Dimension_System (Base_Type (Etyp))
2010 then
2011 Dims_Of_Etyp := Dimensions_Of (Prefix (N));
2013 -- Check the prefix is not dimensionless
2015 if Exists (Dims_Of_Etyp) then
2016 Set_Dimensions (N, Dims_Of_Etyp);
2017 end if;
2018 end if;
2020 -- Remove dimensions from inner expressions, to prevent dimensions
2021 -- table from growing uselessly.
2023 case Nkind (N) is
2024 when N_Attribute_Reference |
2025 N_Indexed_Component =>
2026 declare
2027 Expr : Node_Id;
2028 Exprs : constant List_Id := Expressions (N);
2029 begin
2030 if Present (Exprs) then
2031 Expr := First (Exprs);
2032 while Present (Expr) loop
2033 Remove_Dimensions (Expr);
2034 Next (Expr);
2035 end loop;
2036 end if;
2037 end;
2039 when N_Qualified_Expression |
2040 N_Type_Conversion |
2041 N_Unchecked_Type_Conversion =>
2042 Remove_Dimensions (Expression (N));
2044 when N_Selected_Component =>
2045 Remove_Dimensions (Selector_Name (N));
2047 when others => null;
2048 end case;
2049 end Analyze_Dimension_Has_Etype;
2051 ------------------------------------------
2052 -- Analyze_Dimension_Number_Declaration --
2053 ------------------------------------------
2055 procedure Analyze_Dimension_Number_Declaration (N : Node_Id) is
2056 Expr : constant Node_Id := Expression (N);
2057 Id : constant Entity_Id := Defining_Identifier (N);
2058 Dim_Of_Expr : constant Dimension_Type := Dimensions_Of (Expr);
2060 begin
2061 if Exists (Dim_Of_Expr) then
2062 Set_Dimensions (Id, Dim_Of_Expr);
2063 Set_Etype (Id, Etype (Expr));
2064 end if;
2065 end Analyze_Dimension_Number_Declaration;
2067 ------------------------------------------
2068 -- Analyze_Dimension_Object_Declaration --
2069 ------------------------------------------
2071 procedure Analyze_Dimension_Object_Declaration (N : Node_Id) is
2072 Expr : constant Node_Id := Expression (N);
2073 Id : constant Entity_Id := Defining_Identifier (N);
2074 Etyp : constant Entity_Id := Etype (Id);
2075 Dim_Of_Etyp : constant Dimension_Type := Dimensions_Of (Etyp);
2076 Dim_Of_Expr : Dimension_Type;
2078 procedure Error_Dim_Msg_For_Object_Declaration
2079 (N : Node_Id;
2080 Etyp : Entity_Id;
2081 Expr : Node_Id);
2082 -- Error using Error_Msg_N at node N. Output the dimensions of the
2083 -- type Etyp and of the expression Expr.
2085 ------------------------------------------
2086 -- Error_Dim_Msg_For_Object_Declaration --
2087 ------------------------------------------
2089 procedure Error_Dim_Msg_For_Object_Declaration
2090 (N : Node_Id;
2091 Etyp : Entity_Id;
2092 Expr : Node_Id) is
2093 begin
2094 Error_Msg_N ("dimensions mismatch in object declaration", N);
2095 Error_Msg_N
2096 ("\expected dimension " & Dimensions_Msg_Of (Etyp) & ", found "
2097 & Dimensions_Msg_Of (Expr), Expr);
2098 end Error_Dim_Msg_For_Object_Declaration;
2100 -- Start of processing for Analyze_Dimension_Object_Declaration
2102 begin
2103 -- Expression is present
2105 if Present (Expr) then
2106 Dim_Of_Expr := Dimensions_Of (Expr);
2108 -- Check dimensions match
2110 if Dim_Of_Expr /= Dim_Of_Etyp then
2112 -- Numeric literal case. Issue a warning if the object type is not
2113 -- dimensionless to indicate the literal is treated as if its
2114 -- dimension matches the type dimension.
2116 if Nkind_In (Original_Node (Expr), N_Real_Literal,
2117 N_Integer_Literal)
2118 then
2119 Dim_Warning_For_Numeric_Literal (Expr, Etyp);
2121 -- Case of object is a constant whose type is a dimensioned type
2123 elsif Constant_Present (N) and then not Exists (Dim_Of_Etyp) then
2125 -- Propagate dimension from expression to object entity
2127 Set_Dimensions (Id, Dim_Of_Expr);
2129 -- For all other cases, issue an error message
2131 else
2132 Error_Dim_Msg_For_Object_Declaration (N, Etyp, Expr);
2133 end if;
2134 end if;
2136 -- Removal of dimensions in expression
2138 Remove_Dimensions (Expr);
2139 end if;
2140 end Analyze_Dimension_Object_Declaration;
2142 ---------------------------------------------------
2143 -- Analyze_Dimension_Object_Renaming_Declaration --
2144 ---------------------------------------------------
2146 procedure Analyze_Dimension_Object_Renaming_Declaration (N : Node_Id) is
2147 Renamed_Name : constant Node_Id := Name (N);
2148 Sub_Mark : constant Node_Id := Subtype_Mark (N);
2150 procedure Error_Dim_Msg_For_Object_Renaming_Declaration
2151 (N : Node_Id;
2152 Sub_Mark : Node_Id;
2153 Renamed_Name : Node_Id);
2154 -- Error using Error_Msg_N at node N. Output the dimensions of
2155 -- Sub_Mark and of Renamed_Name.
2157 ---------------------------------------------------
2158 -- Error_Dim_Msg_For_Object_Renaming_Declaration --
2159 ---------------------------------------------------
2161 procedure Error_Dim_Msg_For_Object_Renaming_Declaration
2162 (N : Node_Id;
2163 Sub_Mark : Node_Id;
2164 Renamed_Name : Node_Id) is
2165 begin
2166 Error_Msg_N ("dimensions mismatch in object renaming declaration", N);
2167 Error_Msg_N
2168 ("\expected dimension " & Dimensions_Msg_Of (Sub_Mark) & ", found "
2169 & Dimensions_Msg_Of (Renamed_Name), Renamed_Name);
2170 end Error_Dim_Msg_For_Object_Renaming_Declaration;
2172 -- Start of processing for Analyze_Dimension_Object_Renaming_Declaration
2174 begin
2175 if Dimensions_Of (Renamed_Name) /= Dimensions_Of (Sub_Mark) then
2176 Error_Dim_Msg_For_Object_Renaming_Declaration
2177 (N, Sub_Mark, Renamed_Name);
2178 end if;
2179 end Analyze_Dimension_Object_Renaming_Declaration;
2181 -----------------------------------------------
2182 -- Analyze_Dimension_Simple_Return_Statement --
2183 -----------------------------------------------
2185 procedure Analyze_Dimension_Simple_Return_Statement (N : Node_Id) is
2186 Expr : constant Node_Id := Expression (N);
2187 Return_Ent : constant Entity_Id := Return_Statement_Entity (N);
2188 Return_Etyp : constant Entity_Id :=
2189 Etype (Return_Applies_To (Return_Ent));
2190 Dims_Of_Return_Etyp : constant Dimension_Type :=
2191 Dimensions_Of (Return_Etyp);
2193 procedure Error_Dim_Msg_For_Simple_Return_Statement
2194 (N : Node_Id;
2195 Return_Etyp : Entity_Id;
2196 Expr : Node_Id);
2197 -- Error using Error_Msg_N at node N. Output the dimensions of the
2198 -- returned type Return_Etyp and the returned expression Expr of N.
2200 -----------------------------------------------
2201 -- Error_Dim_Msg_For_Simple_Return_Statement --
2202 -----------------------------------------------
2204 procedure Error_Dim_Msg_For_Simple_Return_Statement
2205 (N : Node_Id;
2206 Return_Etyp : Entity_Id;
2207 Expr : Node_Id)
2209 begin
2210 Error_Msg_N ("dimensions mismatch in return statement", N);
2211 Error_Msg_N
2212 ("\expected dimension " & Dimensions_Msg_Of (Return_Etyp)
2213 & ", found " & Dimensions_Msg_Of (Expr), Expr);
2214 end Error_Dim_Msg_For_Simple_Return_Statement;
2216 -- Start of processing for Analyze_Dimension_Simple_Return_Statement
2218 begin
2219 if Dims_Of_Return_Etyp /= Dimensions_Of (Expr) then
2220 Error_Dim_Msg_For_Simple_Return_Statement (N, Return_Etyp, Expr);
2221 Remove_Dimensions (Expr);
2222 end if;
2223 end Analyze_Dimension_Simple_Return_Statement;
2225 -------------------------------------------
2226 -- Analyze_Dimension_Subtype_Declaration --
2227 -------------------------------------------
2229 procedure Analyze_Dimension_Subtype_Declaration (N : Node_Id) is
2230 Id : constant Entity_Id := Defining_Identifier (N);
2231 Dims_Of_Id : constant Dimension_Type := Dimensions_Of (Id);
2232 Dims_Of_Etyp : Dimension_Type;
2233 Etyp : Node_Id;
2235 begin
2236 -- No constraint case in subtype declaration
2238 if Nkind (Subtype_Indication (N)) /= N_Subtype_Indication then
2239 Etyp := Etype (Subtype_Indication (N));
2240 Dims_Of_Etyp := Dimensions_Of (Etyp);
2242 if Exists (Dims_Of_Etyp) then
2244 -- If subtype already has a dimension (from Aspect_Dimension), it
2245 -- cannot inherit different dimensions from its subtype.
2247 if Exists (Dims_Of_Id) and then Dims_Of_Etyp /= Dims_Of_Id then
2248 Error_Msg_NE
2249 ("subtype& already " & Dimensions_Msg_Of (Id, True), N, Id);
2250 else
2251 Set_Dimensions (Id, Dims_Of_Etyp);
2252 Set_Symbol (Id, Symbol_Of (Etyp));
2253 end if;
2254 end if;
2256 -- Constraint present in subtype declaration
2258 else
2259 Etyp := Etype (Subtype_Mark (Subtype_Indication (N)));
2260 Dims_Of_Etyp := Dimensions_Of (Etyp);
2262 if Exists (Dims_Of_Etyp) then
2263 Set_Dimensions (Id, Dims_Of_Etyp);
2264 Set_Symbol (Id, Symbol_Of (Etyp));
2265 end if;
2266 end if;
2267 end Analyze_Dimension_Subtype_Declaration;
2269 --------------------------------
2270 -- Analyze_Dimension_Unary_Op --
2271 --------------------------------
2273 procedure Analyze_Dimension_Unary_Op (N : Node_Id) is
2274 begin
2275 case Nkind (N) is
2276 when N_Op_Plus | N_Op_Minus | N_Op_Abs =>
2278 -- Propagate the dimension if the operand is not dimensionless
2280 declare
2281 R : constant Node_Id := Right_Opnd (N);
2282 begin
2283 Move_Dimensions (R, N);
2284 end;
2286 when others => null;
2288 end case;
2289 end Analyze_Dimension_Unary_Op;
2291 ---------------------------------
2292 -- Check_Expression_Dimensions --
2293 ---------------------------------
2295 procedure Check_Expression_Dimensions
2296 (Expr : Node_Id;
2297 Typ : Entity_Id)
2299 begin
2300 if Is_Floating_Point_Type (Etype (Expr)) then
2301 Analyze_Dimension (Expr);
2303 if Dimensions_Of (Expr) /= Dimensions_Of (Typ) then
2304 Error_Msg_N ("dimensions mismatch in array aggregate", Expr);
2305 Error_Msg_N
2306 ("\expected dimension " & Dimensions_Msg_Of (Typ)
2307 & ", found " & Dimensions_Msg_Of (Expr), Expr);
2308 end if;
2309 end if;
2310 end Check_Expression_Dimensions;
2312 ---------------------
2313 -- Copy_Dimensions --
2314 ---------------------
2316 procedure Copy_Dimensions (From, To : Node_Id) is
2317 Dims_Of_From : constant Dimension_Type := Dimensions_Of (From);
2319 begin
2320 -- Ignore if not Ada 2012 or beyond
2322 if Ada_Version < Ada_2012 then
2323 return;
2325 -- For Ada 2012, Copy the dimension of 'From to 'To'
2327 elsif Exists (Dims_Of_From) then
2328 Set_Dimensions (To, Dims_Of_From);
2329 end if;
2330 end Copy_Dimensions;
2332 --------------------------
2333 -- Create_Rational_From --
2334 --------------------------
2336 -- RATIONAL ::= [-] NUMERAL [/ NUMERAL]
2338 -- A rational number is a number that can be expressed as the quotient or
2339 -- fraction a/b of two integers, where b is non-zero positive.
2341 function Create_Rational_From
2342 (Expr : Node_Id;
2343 Complain : Boolean) return Rational
2345 Or_Node_Of_Expr : constant Node_Id := Original_Node (Expr);
2346 Result : Rational := No_Rational;
2348 function Process_Minus (N : Node_Id) return Rational;
2349 -- Create a rational from a N_Op_Minus node
2351 function Process_Divide (N : Node_Id) return Rational;
2352 -- Create a rational from a N_Op_Divide node
2354 function Process_Literal (N : Node_Id) return Rational;
2355 -- Create a rational from a N_Integer_Literal node
2357 -------------------
2358 -- Process_Minus --
2359 -------------------
2361 function Process_Minus (N : Node_Id) return Rational is
2362 Right : constant Node_Id := Original_Node (Right_Opnd (N));
2363 Result : Rational;
2365 begin
2366 -- Operand is an integer literal
2368 if Nkind (Right) = N_Integer_Literal then
2369 Result := -Process_Literal (Right);
2371 -- Operand is a divide operator
2373 elsif Nkind (Right) = N_Op_Divide then
2374 Result := -Process_Divide (Right);
2376 else
2377 Result := No_Rational;
2378 end if;
2380 -- Provide minimal semantic information on dimension expressions,
2381 -- even though they have no run-time existence. This is for use by
2382 -- ASIS tools, in particular pretty-printing. If generating code
2383 -- standard operator resolution will take place.
2385 if ASIS_Mode then
2386 Set_Entity (N, Standard_Op_Minus);
2387 Set_Etype (N, Standard_Integer);
2388 end if;
2390 return Result;
2391 end Process_Minus;
2393 --------------------
2394 -- Process_Divide --
2395 --------------------
2397 function Process_Divide (N : Node_Id) return Rational is
2398 Left : constant Node_Id := Original_Node (Left_Opnd (N));
2399 Right : constant Node_Id := Original_Node (Right_Opnd (N));
2400 Left_Rat : Rational;
2401 Result : Rational := No_Rational;
2402 Right_Rat : Rational;
2404 begin
2405 -- Both left and right operands are integer literals
2407 if Nkind (Left) = N_Integer_Literal
2408 and then
2409 Nkind (Right) = N_Integer_Literal
2410 then
2411 Left_Rat := Process_Literal (Left);
2412 Right_Rat := Process_Literal (Right);
2413 Result := Left_Rat / Right_Rat;
2414 end if;
2416 -- Provide minimal semantic information on dimension expressions,
2417 -- even though they have no run-time existence. This is for use by
2418 -- ASIS tools, in particular pretty-printing. If generating code
2419 -- standard operator resolution will take place.
2421 if ASIS_Mode then
2422 Set_Entity (N, Standard_Op_Divide);
2423 Set_Etype (N, Standard_Integer);
2424 end if;
2426 return Result;
2427 end Process_Divide;
2429 ---------------------
2430 -- Process_Literal --
2431 ---------------------
2433 function Process_Literal (N : Node_Id) return Rational is
2434 begin
2435 return +Whole (UI_To_Int (Intval (N)));
2436 end Process_Literal;
2438 -- Start of processing for Create_Rational_From
2440 begin
2441 -- Check the expression is either a division of two integers or an
2442 -- integer itself. Note that the check applies to the original node
2443 -- since the node could have already been rewritten.
2445 -- Integer literal case
2447 if Nkind (Or_Node_Of_Expr) = N_Integer_Literal then
2448 Result := Process_Literal (Or_Node_Of_Expr);
2450 -- Divide operator case
2452 elsif Nkind (Or_Node_Of_Expr) = N_Op_Divide then
2453 Result := Process_Divide (Or_Node_Of_Expr);
2455 -- Minus operator case
2457 elsif Nkind (Or_Node_Of_Expr) = N_Op_Minus then
2458 Result := Process_Minus (Or_Node_Of_Expr);
2459 end if;
2461 -- When Expr cannot be interpreted as a rational and Complain is true,
2462 -- generate an error message.
2464 if Complain and then Result = No_Rational then
2465 Error_Msg_N ("rational expected", Expr);
2466 end if;
2468 return Result;
2469 end Create_Rational_From;
2471 -------------------
2472 -- Dimensions_Of --
2473 -------------------
2475 function Dimensions_Of (N : Node_Id) return Dimension_Type is
2476 begin
2477 return Dimension_Table.Get (N);
2478 end Dimensions_Of;
2480 -----------------------
2481 -- Dimensions_Msg_Of --
2482 -----------------------
2484 function Dimensions_Msg_Of
2485 (N : Node_Id;
2486 Description_Needed : Boolean := False) return String
2488 Dims_Of_N : constant Dimension_Type := Dimensions_Of (N);
2489 Dimensions_Msg : Name_Id;
2490 System : System_Type;
2492 begin
2493 -- Initialization of Name_Buffer
2495 Name_Len := 0;
2497 -- N is not dimensionless
2499 if Exists (Dims_Of_N) then
2500 System := System_Of (Base_Type (Etype (N)));
2502 -- When Description_Needed, add to string "has dimension " before the
2503 -- actual dimension.
2505 if Description_Needed then
2506 Add_Str_To_Name_Buffer ("has dimension ");
2507 end if;
2509 Add_String_To_Name_Buffer
2510 (From_Dim_To_Str_Of_Dim_Symbols (Dims_Of_N, System, True));
2512 -- N is dimensionless
2514 -- When Description_Needed, return "is dimensionless"
2516 elsif Description_Needed then
2517 Add_Str_To_Name_Buffer ("is dimensionless");
2519 -- Otherwise, return "'[']"
2521 else
2522 Add_Str_To_Name_Buffer ("'[']");
2523 end if;
2525 Dimensions_Msg := Name_Find;
2526 return Get_Name_String (Dimensions_Msg);
2527 end Dimensions_Msg_Of;
2529 --------------------------
2530 -- Dimension_Table_Hash --
2531 --------------------------
2533 function Dimension_Table_Hash
2534 (Key : Node_Id) return Dimension_Table_Range
2536 begin
2537 return Dimension_Table_Range (Key mod 511);
2538 end Dimension_Table_Hash;
2540 -------------------------------------
2541 -- Dim_Warning_For_Numeric_Literal --
2542 -------------------------------------
2544 procedure Dim_Warning_For_Numeric_Literal (N : Node_Id; Typ : Entity_Id) is
2545 begin
2546 -- Initialize name buffer
2548 Name_Len := 0;
2550 Add_String_To_Name_Buffer (String_From_Numeric_Literal (N));
2552 -- Insert a blank between the literal and the symbol
2554 Add_Str_To_Name_Buffer (" ");
2555 Add_String_To_Name_Buffer (Symbol_Of (Typ));
2557 Error_Msg_Name_1 := Name_Find;
2558 Error_Msg_N ("assumed to be%%??", N);
2559 end Dim_Warning_For_Numeric_Literal;
2561 ----------------------------------------
2562 -- Eval_Op_Expon_For_Dimensioned_Type --
2563 ----------------------------------------
2565 -- Evaluate the expon operator for real dimensioned type.
2567 -- Note that if the exponent is an integer (denominator = 1) the node is
2568 -- evaluated by the regular Eval_Op_Expon routine (see Sem_Eval).
2570 procedure Eval_Op_Expon_For_Dimensioned_Type
2571 (N : Node_Id;
2572 Btyp : Entity_Id)
2574 R : constant Node_Id := Right_Opnd (N);
2575 R_Value : Rational := No_Rational;
2577 begin
2578 if Is_Real_Type (Btyp) then
2579 R_Value := Create_Rational_From (R, False);
2580 end if;
2582 -- Check that the exponent is not an integer
2584 if R_Value /= No_Rational and then R_Value.Denominator /= 1 then
2585 Eval_Op_Expon_With_Rational_Exponent (N, R_Value);
2586 else
2587 Eval_Op_Expon (N);
2588 end if;
2589 end Eval_Op_Expon_For_Dimensioned_Type;
2591 ------------------------------------------
2592 -- Eval_Op_Expon_With_Rational_Exponent --
2593 ------------------------------------------
2595 -- For dimensioned operand in exponentiation, exponent is allowed to be a
2596 -- Rational and not only an Integer like for dimensionless operands. For
2597 -- that particular case, the left operand is rewritten as a function call
2598 -- using the function Expon_LLF from s-llflex.ads.
2600 procedure Eval_Op_Expon_With_Rational_Exponent
2601 (N : Node_Id;
2602 Exponent_Value : Rational)
2604 Loc : constant Source_Ptr := Sloc (N);
2605 Dims_Of_N : constant Dimension_Type := Dimensions_Of (N);
2606 L : constant Node_Id := Left_Opnd (N);
2607 Etyp_Of_L : constant Entity_Id := Etype (L);
2608 Btyp_Of_L : constant Entity_Id := Base_Type (Etyp_Of_L);
2609 Actual_1 : Node_Id;
2610 Actual_2 : Node_Id;
2611 Dim_Power : Rational;
2612 List_Of_Dims : List_Id;
2613 New_Aspect : Node_Id;
2614 New_Aspects : List_Id;
2615 New_Id : Entity_Id;
2616 New_N : Node_Id;
2617 New_Subtyp_Decl_For_L : Node_Id;
2618 System : System_Type;
2620 begin
2621 -- Case when the operand is not dimensionless
2623 if Exists (Dims_Of_N) then
2625 -- Get the corresponding System_Type to know the exact number of
2626 -- dimensions in the system.
2628 System := System_Of (Btyp_Of_L);
2630 -- Generation of a new subtype with the proper dimensions
2632 -- In order to rewrite the operator as a type conversion, a new
2633 -- dimensioned subtype with the resulting dimensions of the
2634 -- exponentiation must be created.
2636 -- Generate:
2638 -- Btyp_Of_L : constant Entity_Id := Base_Type (Etyp_Of_L);
2639 -- System : constant System_Id :=
2640 -- Get_Dimension_System_Id (Btyp_Of_L);
2641 -- Num_Of_Dims : constant Number_Of_Dimensions :=
2642 -- Dimension_Systems.Table (System).Dimension_Count;
2644 -- subtype T is Btyp_Of_L
2645 -- with
2646 -- Dimension => (
2647 -- Dims_Of_N (1).Numerator / Dims_Of_N (1).Denominator,
2648 -- Dims_Of_N (2).Numerator / Dims_Of_N (2).Denominator,
2649 -- ...
2650 -- Dims_Of_N (Num_Of_Dims).Numerator /
2651 -- Dims_Of_N (Num_Of_Dims).Denominator);
2653 -- Step 1: Generate the new aggregate for the aspect Dimension
2655 New_Aspects := Empty_List;
2657 List_Of_Dims := New_List;
2658 for Position in Dims_Of_N'First .. System.Count loop
2659 Dim_Power := Dims_Of_N (Position);
2660 Append_To (List_Of_Dims,
2661 Make_Op_Divide (Loc,
2662 Left_Opnd =>
2663 Make_Integer_Literal (Loc, Int (Dim_Power.Numerator)),
2664 Right_Opnd =>
2665 Make_Integer_Literal (Loc, Int (Dim_Power.Denominator))));
2666 end loop;
2668 -- Step 2: Create the new Aspect Specification for Aspect Dimension
2670 New_Aspect :=
2671 Make_Aspect_Specification (Loc,
2672 Identifier => Make_Identifier (Loc, Name_Dimension),
2673 Expression => Make_Aggregate (Loc, Expressions => List_Of_Dims));
2675 -- Step 3: Make a temporary identifier for the new subtype
2677 New_Id := Make_Temporary (Loc, 'T');
2678 Set_Is_Internal (New_Id);
2680 -- Step 4: Declaration of the new subtype
2682 New_Subtyp_Decl_For_L :=
2683 Make_Subtype_Declaration (Loc,
2684 Defining_Identifier => New_Id,
2685 Subtype_Indication => New_Occurrence_Of (Btyp_Of_L, Loc));
2687 Append (New_Aspect, New_Aspects);
2688 Set_Parent (New_Aspects, New_Subtyp_Decl_For_L);
2689 Set_Aspect_Specifications (New_Subtyp_Decl_For_L, New_Aspects);
2691 Analyze (New_Subtyp_Decl_For_L);
2693 -- Case where the operand is dimensionless
2695 else
2696 New_Id := Btyp_Of_L;
2697 end if;
2699 -- Replacement of N by New_N
2701 -- Generate:
2703 -- Actual_1 := Long_Long_Float (L),
2705 -- Actual_2 := Long_Long_Float (Exponent_Value.Numerator) /
2706 -- Long_Long_Float (Exponent_Value.Denominator);
2708 -- (T (Expon_LLF (Actual_1, Actual_2)));
2710 -- where T is the subtype declared in step 1
2712 -- The node is rewritten as a type conversion
2714 -- Step 1: Creation of the two parameters of Expon_LLF function call
2716 Actual_1 :=
2717 Make_Type_Conversion (Loc,
2718 Subtype_Mark => New_Occurrence_Of (Standard_Long_Long_Float, Loc),
2719 Expression => Relocate_Node (L));
2721 Actual_2 :=
2722 Make_Op_Divide (Loc,
2723 Left_Opnd =>
2724 Make_Real_Literal (Loc,
2725 UR_From_Uint (UI_From_Int (Int (Exponent_Value.Numerator)))),
2726 Right_Opnd =>
2727 Make_Real_Literal (Loc,
2728 UR_From_Uint (UI_From_Int (Int (Exponent_Value.Denominator)))));
2730 -- Step 2: Creation of New_N
2732 New_N :=
2733 Make_Type_Conversion (Loc,
2734 Subtype_Mark => New_Occurrence_Of (New_Id, Loc),
2735 Expression =>
2736 Make_Function_Call (Loc,
2737 Name => New_Occurrence_Of (RTE (RE_Expon_LLF), Loc),
2738 Parameter_Associations => New_List (
2739 Actual_1, Actual_2)));
2741 -- Step 3: Rewrite N with the result
2743 Rewrite (N, New_N);
2744 Set_Etype (N, New_Id);
2745 Analyze_And_Resolve (N, New_Id);
2746 end Eval_Op_Expon_With_Rational_Exponent;
2748 ------------
2749 -- Exists --
2750 ------------
2752 function Exists (Dim : Dimension_Type) return Boolean is
2753 begin
2754 return Dim /= Null_Dimension;
2755 end Exists;
2757 function Exists (Str : String_Id) return Boolean is
2758 begin
2759 return Str /= No_String;
2760 end Exists;
2762 function Exists (Sys : System_Type) return Boolean is
2763 begin
2764 return Sys /= Null_System;
2765 end Exists;
2767 ---------------------------------
2768 -- Expand_Put_Call_With_Symbol --
2769 ---------------------------------
2771 -- For procedure Put (resp. Put_Dim_Of) and function Image, defined in
2772 -- System.Dim.Float_IO or System.Dim.Integer_IO, the default string
2773 -- parameter is rewritten to include the unit symbol (or the dimension
2774 -- symbols if not a defined quantity) in the output of a dimensioned
2775 -- object. If a value is already supplied by the user for the parameter
2776 -- Symbol, it is used as is.
2778 -- Case 1. Item is dimensionless
2780 -- * Put : Item appears without a suffix
2782 -- * Put_Dim_Of : the output is []
2784 -- Obj : Mks_Type := 2.6;
2785 -- Put (Obj, 1, 1, 0);
2786 -- Put_Dim_Of (Obj);
2788 -- The corresponding outputs are:
2789 -- $2.6
2790 -- $[]
2792 -- Case 2. Item has a dimension
2794 -- * Put : If the type of Item is a dimensioned subtype whose
2795 -- symbol is not empty, then the symbol appears as a
2796 -- suffix. Otherwise, a new string is created and appears
2797 -- as a suffix of Item. This string results in the
2798 -- successive concatanations between each unit symbol
2799 -- raised by its corresponding dimension power from the
2800 -- dimensions of Item.
2802 -- * Put_Dim_Of : The output is a new string resulting in the successive
2803 -- concatanations between each dimension symbol raised by
2804 -- its corresponding dimension power from the dimensions of
2805 -- Item.
2807 -- subtype Random is Mks_Type
2808 -- with
2809 -- Dimension => (
2810 -- Meter => 3,
2811 -- Candela => -1,
2812 -- others => 0);
2814 -- Obj : Random := 5.0;
2815 -- Put (Obj);
2816 -- Put_Dim_Of (Obj);
2818 -- The corresponding outputs are:
2819 -- $5.0 m**3.cd**(-1)
2820 -- $[l**3.J**(-1)]
2822 -- The function Image returns the string identical to that produced by
2823 -- a call to Put whose first parameter is a string.
2825 procedure Expand_Put_Call_With_Symbol (N : Node_Id) is
2826 Actuals : constant List_Id := Parameter_Associations (N);
2827 Loc : constant Source_Ptr := Sloc (N);
2828 Name_Call : constant Node_Id := Name (N);
2829 New_Actuals : constant List_Id := New_List;
2830 Actual : Node_Id;
2831 Dims_Of_Actual : Dimension_Type;
2832 Etyp : Entity_Id;
2833 New_Str_Lit : Node_Id := Empty;
2834 Symbols : String_Id;
2836 Is_Put_Dim_Of : Boolean := False;
2837 -- This flag is used in order to differentiate routines Put and
2838 -- Put_Dim_Of. Set to True if the procedure is one of the Put_Dim_Of
2839 -- defined in System.Dim.Float_IO or System.Dim.Integer_IO.
2841 function Has_Symbols return Boolean;
2842 -- Return True if the current Put call already has a parameter
2843 -- association for parameter "Symbols" with the correct string of
2844 -- symbols.
2846 function Is_Procedure_Put_Call return Boolean;
2847 -- Return True if the current call is a call of an instantiation of a
2848 -- procedure Put defined in the package System.Dim.Float_IO and
2849 -- System.Dim.Integer_IO.
2851 function Item_Actual return Node_Id;
2852 -- Return the item actual parameter node in the output call
2854 -----------------
2855 -- Has_Symbols --
2856 -----------------
2858 function Has_Symbols return Boolean is
2859 Actual : Node_Id;
2860 Actual_Str : Node_Id;
2862 begin
2863 -- Look for a symbols parameter association in the list of actuals
2865 Actual := First (Actuals);
2866 while Present (Actual) loop
2868 -- Positional parameter association case when the actual is a
2869 -- string literal.
2871 if Nkind (Actual) = N_String_Literal then
2872 Actual_Str := Actual;
2874 -- Named parameter association case when selector name is Symbol
2876 elsif Nkind (Actual) = N_Parameter_Association
2877 and then Chars (Selector_Name (Actual)) = Name_Symbol
2878 then
2879 Actual_Str := Explicit_Actual_Parameter (Actual);
2881 -- Ignore all other cases
2883 else
2884 Actual_Str := Empty;
2885 end if;
2887 if Present (Actual_Str) then
2889 -- Return True if the actual comes from source or if the string
2890 -- of symbols doesn't have the default value (i.e. it is ""),
2891 -- in which case it is used as suffix of the generated string.
2893 if Comes_From_Source (Actual)
2894 or else String_Length (Strval (Actual_Str)) /= 0
2895 then
2896 return True;
2898 else
2899 return False;
2900 end if;
2901 end if;
2903 Next (Actual);
2904 end loop;
2906 -- At this point, the call has no parameter association. Look to the
2907 -- last actual since the symbols parameter is the last one.
2909 return Nkind (Last (Actuals)) = N_String_Literal;
2910 end Has_Symbols;
2912 ---------------------------
2913 -- Is_Procedure_Put_Call --
2914 ---------------------------
2916 function Is_Procedure_Put_Call return Boolean is
2917 Ent : Entity_Id;
2918 Loc : Source_Ptr;
2920 begin
2921 -- There are three different Put (resp. Put_Dim_Of) routines in each
2922 -- generic dim IO package. Verify the current procedure call is one
2923 -- of them.
2925 if Is_Entity_Name (Name_Call) then
2926 Ent := Entity (Name_Call);
2928 -- Get the original subprogram entity following the renaming chain
2930 if Present (Alias (Ent)) then
2931 Ent := Alias (Ent);
2932 end if;
2934 Loc := Sloc (Ent);
2936 -- Check the name of the entity subprogram is Put (resp.
2937 -- Put_Dim_Of) and verify this entity is located in either
2938 -- System.Dim.Float_IO or System.Dim.Integer_IO.
2940 if Loc > No_Location
2941 and then Is_Dim_IO_Package_Entity
2942 (Cunit_Entity (Get_Source_Unit (Loc)))
2943 then
2944 if Chars (Ent) = Name_Put_Dim_Of then
2945 Is_Put_Dim_Of := True;
2946 return True;
2948 elsif Chars (Ent) = Name_Put
2949 or else Chars (Ent) = Name_Image
2950 then
2951 return True;
2952 end if;
2953 end if;
2954 end if;
2956 return False;
2957 end Is_Procedure_Put_Call;
2959 -----------------
2960 -- Item_Actual --
2961 -----------------
2963 function Item_Actual return Node_Id is
2964 Actual : Node_Id;
2966 begin
2967 -- Look for the item actual as a parameter association
2969 Actual := First (Actuals);
2970 while Present (Actual) loop
2971 if Nkind (Actual) = N_Parameter_Association
2972 and then Chars (Selector_Name (Actual)) = Name_Item
2973 then
2974 return Explicit_Actual_Parameter (Actual);
2975 end if;
2977 Next (Actual);
2978 end loop;
2980 -- Case where the item has been defined without an association
2982 Actual := First (Actuals);
2984 -- Depending on the procedure Put, Item actual could be first or
2985 -- second in the list of actuals.
2987 if Has_Dimension_System (Base_Type (Etype (Actual))) then
2988 return Actual;
2989 else
2990 return Next (Actual);
2991 end if;
2992 end Item_Actual;
2994 -- Start of processing for Expand_Put_Call_With_Symbol
2996 begin
2997 if Is_Procedure_Put_Call and then not Has_Symbols then
2998 Actual := Item_Actual;
2999 Dims_Of_Actual := Dimensions_Of (Actual);
3000 Etyp := Etype (Actual);
3002 -- Put_Dim_Of case
3004 if Is_Put_Dim_Of then
3006 -- Check that the item is not dimensionless
3008 -- Create the new String_Literal with the new String_Id generated
3009 -- by the routine From_Dim_To_Str_Of_Dim_Symbols.
3011 if Exists (Dims_Of_Actual) then
3012 New_Str_Lit :=
3013 Make_String_Literal (Loc,
3014 From_Dim_To_Str_Of_Dim_Symbols
3015 (Dims_Of_Actual, System_Of (Base_Type (Etyp))));
3017 -- If dimensionless, the output is []
3019 else
3020 New_Str_Lit :=
3021 Make_String_Literal (Loc, "[]");
3022 end if;
3024 -- Put case
3026 else
3027 -- Add the symbol as a suffix of the value if the subtype has a
3028 -- unit symbol or if the parameter is not dimensionless.
3030 if Exists (Symbol_Of (Etyp)) then
3031 Symbols := Symbol_Of (Etyp);
3032 else
3033 Symbols := From_Dim_To_Str_Of_Unit_Symbols
3034 (Dims_Of_Actual, System_Of (Base_Type (Etyp)));
3035 end if;
3037 -- Check Symbols exists
3039 if Exists (Symbols) then
3040 Start_String;
3042 -- Put a space between the value and the dimension
3044 Store_String_Char (' ');
3045 Store_String_Chars (Symbols);
3046 New_Str_Lit := Make_String_Literal (Loc, End_String);
3047 end if;
3048 end if;
3050 if Present (New_Str_Lit) then
3052 -- Insert all actuals in New_Actuals
3054 Actual := First (Actuals);
3055 while Present (Actual) loop
3057 -- Copy every actuals in New_Actuals except the Symbols
3058 -- parameter association.
3060 if Nkind (Actual) = N_Parameter_Association
3061 and then Chars (Selector_Name (Actual)) /= Name_Symbol
3062 then
3063 Append_To (New_Actuals,
3064 Make_Parameter_Association (Loc,
3065 Selector_Name => New_Copy (Selector_Name (Actual)),
3066 Explicit_Actual_Parameter =>
3067 New_Copy (Explicit_Actual_Parameter (Actual))));
3069 elsif Nkind (Actual) /= N_Parameter_Association then
3070 Append_To (New_Actuals, New_Copy (Actual));
3071 end if;
3073 Next (Actual);
3074 end loop;
3076 -- Create new Symbols param association and append to New_Actuals
3078 Append_To (New_Actuals,
3079 Make_Parameter_Association (Loc,
3080 Selector_Name => Make_Identifier (Loc, Name_Symbol),
3081 Explicit_Actual_Parameter => New_Str_Lit));
3083 -- Rewrite and analyze the procedure call
3085 if Chars (Name_Call) = Name_Image then
3086 Rewrite (N,
3087 Make_Function_Call (Loc,
3088 Name => New_Copy (Name_Call),
3089 Parameter_Associations => New_Actuals));
3090 Analyze_And_Resolve (N);
3091 else
3092 Rewrite (N,
3093 Make_Procedure_Call_Statement (Loc,
3094 Name => New_Copy (Name_Call),
3095 Parameter_Associations => New_Actuals));
3096 Analyze (N);
3097 end if;
3099 end if;
3100 end if;
3101 end Expand_Put_Call_With_Symbol;
3103 ------------------------------------
3104 -- From_Dim_To_Str_Of_Dim_Symbols --
3105 ------------------------------------
3107 -- Given a dimension vector and the corresponding dimension system, create
3108 -- a String_Id to output dimension symbols corresponding to the dimensions
3109 -- Dims. If In_Error_Msg is True, there is a special handling for character
3110 -- asterisk * which is an insertion character in error messages.
3112 function From_Dim_To_Str_Of_Dim_Symbols
3113 (Dims : Dimension_Type;
3114 System : System_Type;
3115 In_Error_Msg : Boolean := False) return String_Id
3117 Dim_Power : Rational;
3118 First_Dim : Boolean := True;
3120 procedure Store_String_Oexpon;
3121 -- Store the expon operator symbol "**" in the string. In error
3122 -- messages, asterisk * is a special character and must be quoted
3123 -- to be placed literally into the message.
3125 -------------------------
3126 -- Store_String_Oexpon --
3127 -------------------------
3129 procedure Store_String_Oexpon is
3130 begin
3131 if In_Error_Msg then
3132 Store_String_Chars ("'*'*");
3133 else
3134 Store_String_Chars ("**");
3135 end if;
3136 end Store_String_Oexpon;
3138 -- Start of processing for From_Dim_To_Str_Of_Dim_Symbols
3140 begin
3141 -- Initialization of the new String_Id
3143 Start_String;
3145 -- Store the dimension symbols inside boxes
3147 if In_Error_Msg then
3148 Store_String_Chars ("'[");
3149 else
3150 Store_String_Char ('[');
3151 end if;
3153 for Position in Dimension_Type'Range loop
3154 Dim_Power := Dims (Position);
3155 if Dim_Power /= Zero then
3157 if First_Dim then
3158 First_Dim := False;
3159 else
3160 Store_String_Char ('.');
3161 end if;
3163 Store_String_Chars (System.Dim_Symbols (Position));
3165 -- Positive dimension case
3167 if Dim_Power.Numerator > 0 then
3169 -- Integer case
3171 if Dim_Power.Denominator = 1 then
3172 if Dim_Power.Numerator /= 1 then
3173 Store_String_Oexpon;
3174 Store_String_Int (Int (Dim_Power.Numerator));
3175 end if;
3177 -- Rational case when denominator /= 1
3179 else
3180 Store_String_Oexpon;
3181 Store_String_Char ('(');
3182 Store_String_Int (Int (Dim_Power.Numerator));
3183 Store_String_Char ('/');
3184 Store_String_Int (Int (Dim_Power.Denominator));
3185 Store_String_Char (')');
3186 end if;
3188 -- Negative dimension case
3190 else
3191 Store_String_Oexpon;
3192 Store_String_Char ('(');
3193 Store_String_Char ('-');
3194 Store_String_Int (Int (-Dim_Power.Numerator));
3196 -- Integer case
3198 if Dim_Power.Denominator = 1 then
3199 Store_String_Char (')');
3201 -- Rational case when denominator /= 1
3203 else
3204 Store_String_Char ('/');
3205 Store_String_Int (Int (Dim_Power.Denominator));
3206 Store_String_Char (')');
3207 end if;
3208 end if;
3209 end if;
3210 end loop;
3212 if In_Error_Msg then
3213 Store_String_Chars ("']");
3214 else
3215 Store_String_Char (']');
3216 end if;
3218 return End_String;
3219 end From_Dim_To_Str_Of_Dim_Symbols;
3221 -------------------------------------
3222 -- From_Dim_To_Str_Of_Unit_Symbols --
3223 -------------------------------------
3225 -- Given a dimension vector and the corresponding dimension system,
3226 -- create a String_Id to output the unit symbols corresponding to the
3227 -- dimensions Dims.
3229 function From_Dim_To_Str_Of_Unit_Symbols
3230 (Dims : Dimension_Type;
3231 System : System_Type) return String_Id
3233 Dim_Power : Rational;
3234 First_Dim : Boolean := True;
3236 begin
3237 -- Return No_String if dimensionless
3239 if not Exists (Dims) then
3240 return No_String;
3241 end if;
3243 -- Initialization of the new String_Id
3245 Start_String;
3247 for Position in Dimension_Type'Range loop
3248 Dim_Power := Dims (Position);
3250 if Dim_Power /= Zero then
3251 if First_Dim then
3252 First_Dim := False;
3253 else
3254 Store_String_Char ('.');
3255 end if;
3257 Store_String_Chars (System.Unit_Symbols (Position));
3259 -- Positive dimension case
3261 if Dim_Power.Numerator > 0 then
3263 -- Integer case
3265 if Dim_Power.Denominator = 1 then
3266 if Dim_Power.Numerator /= 1 then
3267 Store_String_Chars ("**");
3268 Store_String_Int (Int (Dim_Power.Numerator));
3269 end if;
3271 -- Rational case when denominator /= 1
3273 else
3274 Store_String_Chars ("**");
3275 Store_String_Char ('(');
3276 Store_String_Int (Int (Dim_Power.Numerator));
3277 Store_String_Char ('/');
3278 Store_String_Int (Int (Dim_Power.Denominator));
3279 Store_String_Char (')');
3280 end if;
3282 -- Negative dimension case
3284 else
3285 Store_String_Chars ("**");
3286 Store_String_Char ('(');
3287 Store_String_Char ('-');
3288 Store_String_Int (Int (-Dim_Power.Numerator));
3290 -- Integer case
3292 if Dim_Power.Denominator = 1 then
3293 Store_String_Char (')');
3295 -- Rational case when denominator /= 1
3297 else
3298 Store_String_Char ('/');
3299 Store_String_Int (Int (Dim_Power.Denominator));
3300 Store_String_Char (')');
3301 end if;
3302 end if;
3303 end if;
3304 end loop;
3306 return End_String;
3307 end From_Dim_To_Str_Of_Unit_Symbols;
3309 ---------
3310 -- GCD --
3311 ---------
3313 function GCD (Left, Right : Whole) return Int is
3314 L : Whole;
3315 R : Whole;
3317 begin
3318 L := Left;
3319 R := Right;
3320 while R /= 0 loop
3321 L := L mod R;
3323 if L = 0 then
3324 return Int (R);
3325 end if;
3327 R := R mod L;
3328 end loop;
3330 return Int (L);
3331 end GCD;
3333 --------------------------
3334 -- Has_Dimension_System --
3335 --------------------------
3337 function Has_Dimension_System (Typ : Entity_Id) return Boolean is
3338 begin
3339 return Exists (System_Of (Typ));
3340 end Has_Dimension_System;
3342 ------------------------------
3343 -- Is_Dim_IO_Package_Entity --
3344 ------------------------------
3346 function Is_Dim_IO_Package_Entity (E : Entity_Id) return Boolean is
3347 begin
3348 -- Check the package entity corresponds to System.Dim.Float_IO or
3349 -- System.Dim.Integer_IO.
3351 return
3352 Is_RTU (E, System_Dim_Float_IO)
3353 or else
3354 Is_RTU (E, System_Dim_Integer_IO);
3355 end Is_Dim_IO_Package_Entity;
3357 -------------------------------------
3358 -- Is_Dim_IO_Package_Instantiation --
3359 -------------------------------------
3361 function Is_Dim_IO_Package_Instantiation (N : Node_Id) return Boolean is
3362 Gen_Id : constant Node_Id := Name (N);
3364 begin
3365 -- Check that the instantiated package is either System.Dim.Float_IO
3366 -- or System.Dim.Integer_IO.
3368 return
3369 Is_Entity_Name (Gen_Id)
3370 and then Is_Dim_IO_Package_Entity (Entity (Gen_Id));
3371 end Is_Dim_IO_Package_Instantiation;
3373 ----------------
3374 -- Is_Invalid --
3375 ----------------
3377 function Is_Invalid (Position : Dimension_Position) return Boolean is
3378 begin
3379 return Position = Invalid_Position;
3380 end Is_Invalid;
3382 ---------------------
3383 -- Move_Dimensions --
3384 ---------------------
3386 procedure Move_Dimensions (From, To : Node_Id) is
3387 begin
3388 if Ada_Version < Ada_2012 then
3389 return;
3390 end if;
3392 -- Copy the dimension of 'From to 'To' and remove dimension of 'From'
3394 Copy_Dimensions (From, To);
3395 Remove_Dimensions (From);
3396 end Move_Dimensions;
3398 ------------
3399 -- Reduce --
3400 ------------
3402 function Reduce (X : Rational) return Rational is
3403 begin
3404 if X.Numerator = 0 then
3405 return Zero;
3406 end if;
3408 declare
3409 G : constant Int := GCD (X.Numerator, X.Denominator);
3410 begin
3411 return Rational'(Numerator => Whole (Int (X.Numerator) / G),
3412 Denominator => Whole (Int (X.Denominator) / G));
3413 end;
3414 end Reduce;
3416 -----------------------
3417 -- Remove_Dimensions --
3418 -----------------------
3420 procedure Remove_Dimensions (N : Node_Id) is
3421 Dims_Of_N : constant Dimension_Type := Dimensions_Of (N);
3422 begin
3423 if Exists (Dims_Of_N) then
3424 Dimension_Table.Remove (N);
3425 end if;
3426 end Remove_Dimensions;
3428 -----------------------------------
3429 -- Remove_Dimension_In_Statement --
3430 -----------------------------------
3432 -- Removal of dimension in statement as part of the Analyze_Statements
3433 -- routine (see package Sem_Ch5).
3435 procedure Remove_Dimension_In_Statement (Stmt : Node_Id) is
3436 begin
3437 if Ada_Version < Ada_2012 then
3438 return;
3439 end if;
3441 -- Remove dimension in parameter specifications for accept statement
3443 if Nkind (Stmt) = N_Accept_Statement then
3444 declare
3445 Param : Node_Id := First (Parameter_Specifications (Stmt));
3446 begin
3447 while Present (Param) loop
3448 Remove_Dimensions (Param);
3449 Next (Param);
3450 end loop;
3451 end;
3453 -- Remove dimension of name and expression in assignments
3455 elsif Nkind (Stmt) = N_Assignment_Statement then
3456 Remove_Dimensions (Expression (Stmt));
3457 Remove_Dimensions (Name (Stmt));
3458 end if;
3459 end Remove_Dimension_In_Statement;
3461 --------------------
3462 -- Set_Dimensions --
3463 --------------------
3465 procedure Set_Dimensions (N : Node_Id; Val : Dimension_Type) is
3466 begin
3467 pragma Assert (OK_For_Dimension (Nkind (N)));
3468 pragma Assert (Exists (Val));
3470 Dimension_Table.Set (N, Val);
3471 end Set_Dimensions;
3473 ----------------
3474 -- Set_Symbol --
3475 ----------------
3477 procedure Set_Symbol (E : Entity_Id; Val : String_Id) is
3478 begin
3479 Symbol_Table.Set (E, Val);
3480 end Set_Symbol;
3482 ---------------------------------
3483 -- String_From_Numeric_Literal --
3484 ---------------------------------
3486 function String_From_Numeric_Literal (N : Node_Id) return String_Id is
3487 Loc : constant Source_Ptr := Sloc (N);
3488 Sbuffer : constant Source_Buffer_Ptr :=
3489 Source_Text (Get_Source_File_Index (Loc));
3490 Src_Ptr : Source_Ptr := Loc;
3492 C : Character := Sbuffer (Src_Ptr);
3493 -- Current source program character
3495 function Belong_To_Numeric_Literal (C : Character) return Boolean;
3496 -- Return True if C belongs to a numeric literal
3498 -------------------------------
3499 -- Belong_To_Numeric_Literal --
3500 -------------------------------
3502 function Belong_To_Numeric_Literal (C : Character) return Boolean is
3503 begin
3504 case C is
3505 when '0' .. '9' |
3506 '_' |
3507 '.' |
3508 'e' |
3509 '#' |
3510 'A' |
3511 'B' |
3512 'C' |
3513 'D' |
3514 'E' |
3515 'F' =>
3516 return True;
3518 -- Make sure '+' or '-' is part of an exponent.
3520 when '+' | '-' =>
3521 declare
3522 Prev_C : constant Character := Sbuffer (Src_Ptr - 1);
3523 begin
3524 return Prev_C = 'e' or else Prev_C = 'E';
3525 end;
3527 -- All other character doesn't belong to a numeric literal
3529 when others =>
3530 return False;
3531 end case;
3532 end Belong_To_Numeric_Literal;
3534 -- Start of processing for String_From_Numeric_Literal
3536 begin
3537 Start_String;
3538 while Belong_To_Numeric_Literal (C) loop
3539 Store_String_Char (C);
3540 Src_Ptr := Src_Ptr + 1;
3541 C := Sbuffer (Src_Ptr);
3542 end loop;
3544 return End_String;
3545 end String_From_Numeric_Literal;
3547 ---------------
3548 -- Symbol_Of --
3549 ---------------
3551 function Symbol_Of (E : Entity_Id) return String_Id is
3552 Subtype_Symbol : constant String_Id := Symbol_Table.Get (E);
3553 begin
3554 if Subtype_Symbol /= No_String then
3555 return Subtype_Symbol;
3556 else
3557 return From_Dim_To_Str_Of_Unit_Symbols
3558 (Dimensions_Of (E), System_Of (Base_Type (E)));
3559 end if;
3560 end Symbol_Of;
3562 -----------------------
3563 -- Symbol_Table_Hash --
3564 -----------------------
3566 function Symbol_Table_Hash (Key : Entity_Id) return Symbol_Table_Range is
3567 begin
3568 return Symbol_Table_Range (Key mod 511);
3569 end Symbol_Table_Hash;
3571 ---------------
3572 -- System_Of --
3573 ---------------
3575 function System_Of (E : Entity_Id) return System_Type is
3576 Type_Decl : constant Node_Id := Parent (E);
3578 begin
3579 -- Look for Type_Decl in System_Table
3581 for Dim_Sys in 1 .. System_Table.Last loop
3582 if Type_Decl = System_Table.Table (Dim_Sys).Type_Decl then
3583 return System_Table.Table (Dim_Sys);
3584 end if;
3585 end loop;
3587 return Null_System;
3588 end System_Of;
3590 end Sem_Dim;