Inconsistent argument passing mode - ada

Consider the following code (which compile with GCC 4.7.4):
procedure Main is
procedure Sub_Proc(N : in out Integer) is
M : Integer;
begin
M := N;
end;
procedure Proc(N : out Integer) is
begin
Sub_Proc(N);
end;
N : Integer;
begin
Proc(N);
end Main;
The procedure Proc is supposed to ensure that the argument N which is an out argument will never be read inside his body. But it passes this argument to a procedure Sub_Proc which takes an in out argument, so potentially the previous argument will be read inside this procedure whereas the calling procedure ensured the opposite.
Is it a GCC bug or an Ada standard specificity ?

You’ll have received a warning on the Sub_Proc(N); call: "N" may be referenced before it has a value. So the compiler was trying to help!
In Ada 83, your program would have been illegal: 6.4.1(3) says "for the mode in out, the variable must not be a formal parameter of mode out”. Indeed, using -gnat83, and after a minor rearrangement of the code to allow it to compile, the equivalent to the above warning is the error (Ada 83) illegal reading of out parameter.
In Ada 95 and Ada 2012 it is OK to read the value of an out parameter after it has been assigned; in ARM95 6.4.1(15) we find that the value starts out uninitialized (as indicated by the warning message noted above), so using it is a Bad Idea.
So the answer is, GNAT’s behaviour conforms with the standard.

Related

Ada complaining that I've added a volatile object in a function call to generic type when not volatile

So I've got the following declaration:
record
String1 : String (1 .. 64);
String2 : String (1 .. 64);
Timestamp : Time;
Int1 : Long_Long_Integer;
String3 : Unbounded_String;
end record;
And it's used in
package My_Vectors is new Vectors (Index_Type => Positive, Element_Type => Object);
which yields the compilation error:
volatile object cannot act as actual in a call (SPARK RM 7.1.3(10))
Now, Clock is volatile which is used. However I've removed the call to Clock and I still get the same result.
Also, I've tried replacing the Object type with a type of Integer and I don't have any complaints from the Ada compiler. Could someone explain this as I can't see how this is putting a volatile object into an actual anywhere please.
Just tried using the following record and I get the same result:
type My_Record is
record
A: Integer;
B: Integer;
C: String(1 .. 64);
end record;
The standard Ada containers are not supported in SPARK (see SPARK RM 14.8).
Use the SPARK compatible container Ada.Containers.Formal_Vectors instead (see also here and here).
Regarding the compiler error: the current implementation of Ada.Containers.Vector uses atomic operations to improve performance (see here and here). These atomic operations operate (in this case) on variables of type System.Atomic_Counters.Atomic_Unsigned (see here). This type is declared as Atomic and therefore volatile (see RM 8(3)).

Ada.Containers.Vectors not working with GNAT GPL 2017

I am trying to compile this code:
with Ada.Containers.Vectors;
procedure Test is
type My_Type is range -1 .. Integer'Last;
package My_Vectors is new Ada.Containers.Vectors (Positive, My_Type);
Vector : My_Vectors.Vector;
begin
Vector.Append (-1);
end Test;
gnatmake test.adb gives this output:
gcc -c test.adb
a-convec.adb:1553:33: missing operand
gnatmake: "test.adb" compilation error
The error message leads to this procedure in the stdlib's implementation:
procedure Insert
(Container : in out Vector;
Before : Extended_Index;
Count : Count_Type := 1)
is
New_Item : Element_Type := <>; -- << here
pragma Warnings (Off, New_Item);
begin
Insert (Container, Before, New_Item, Count);
end Insert;
It looks fine. I don't understand the error message, what's wrong here? Is it a bug in the stdlib?
Looks like this file has been tampered with…
Summarizing the evidence,
Multiple comments report no problem with GNAT versions going back as far as 4.9.1.
The initialization marked << here is a compile-time error, as the compound delimiter <>, named box, is not valid in an expression used in assignment.
Based on How gnatmake Works, a-convec.adb would only be recompiled if it were modified after the corresponding .ali file.
Going forward, you might
Check the modification dates of a-convec.adb and a-convec.ali, found in the adainclude and adalib directories, respectively.
Reinstall the compiler.
Notify upstream maintainers if warranted.

Error instantiating generic procedure

Hello i m creating generic procedure which will swap 2 numbers below is my code please help me to fix it.. i am new ada programming please skip if any typo mistake because i m posting this questn frm mobile i dnt have net on my system
swap.ads
generic
type t is private;
procedure swap(l,r:in out t);
swap.adb
procedure swap(l,r:in out t) is
temp:t:=l;
begin
l:=r;
r:=temp;
end swap;
swap_main.adb
v with swap;
procedure swap_main is
procedure swap_i is new swap(t);
i1,i2:interger;
begin
swap_i(i1,i2):
end swap_main;
Leaving aside the simple typos (v with swap, interger, and the last colon): the thing about instantiating a generic is that you have to supply actuals for the formals.
In this case, you say (after adjusting case and spacing to the generally-accepted norm)
generic
type T is private;
procedure Swap (L, R : in out T);
in which T is the formal parameter, which expects assignment and the equality operator ”=“ to be available in the actual.
But in your instantiation you say
procedure Swap_I is new Swap (T);
and the compiler says
rahul.ada:12:34: "T" is undefined
rahul.ada:12:34: instantiation abandoned
rahul.ada:15:04: "Swap_I" is undefined
rahul.ada:15:04: possible misspelling of "Swap_"
gnatmake: "swap_main.adb" compilation error
The second message explains the third. The fourth message is a failed attempt by the compiler to be helpful (Swap_ isn’t a legal identifier, after all).
The first message is the key: there is no type T visible to Swap_Main that is satisfactory as an actual for Swap’s formal parameter T.
I think on the whole that you should have written
procedure Swap_I is new Swap (Integer);
to give you a procedure capable of swapping integers.
“Named association” (Ada 95 Quality and Style Guide, section 5.2.2) would make your intention clearer:
procedure Swap_I is new Swap (T => Integer);

Ada Modeless Subprogram Parameters

If a parameter in Ada is left modeless, what happens?
what is the difference between
procedure my_func ( param_1 : in param_type )
and
procedure my_func ( param_1 : param_type )
I am new to ada and have been writing most of my procedures as the latter. The program compiles and runs as expected.
There is no difference - if no parameter mode is given, the compiler assumes "in".
See http://www.ada-auth.org/standards/12rm/html/RM-6-1.html line beginning 18/3.
-- Martin
As suggested by Martin, the default mode is 'in' if not provided.
I would like to add that if possible, you can sometimes experiment with things about which you are doubtful.
like look at the below simple code, I have not given any mode to the arguement 'no_1'.
And as seen I am assigning value of 'no_2' to it.
with Ada.Text_IO; use Ada.Text_IO;
procedure just_testing is
procedure get_value (no_1 : Integer);
procedure get_value (no_1 : Integer) is
no_2 : Integer := 2;
begin
no_1 := no_2;
end get_value;
begin
Put("auto mode");
end just_testing;
And when I compile this code, look what we get as error.
>gnatmake just_testing.adb
gcc -c just_testing.adb
just_testing.adb:10:09: assignment to "in" mode parameter not allowed
gnatmake: "just_testing.adb" compilation error
So, compiler makes it clear that the default mode is 'in', as we can not assign any value to argument with mode in.

The use of IN OUT in Ada

Given below is some code in ada
with TYPE_VECT_B; use TYPE_VECT_B;
Package TEST01 is
procedure TEST01
( In_State : IN VECT_B ;
Out_State : IN OUT VECT_B );
function TEST02
( In_State : IN VECT_B ) return Boolean ;
end TEST01;
The TYPE_VECT_B package specification and body is also defined below
Package TYPE_VECT_B is
type VECT_B is array (INTEGER range <>) OF BOOLEAN ;
rounded_data : float ;
count : integer ;
trace : integer ;
end TYPE_VECT_B;
Package BODY TYPE_VECT_B is
begin
null;
end TYPE_VECT_B;
What does the variable In_State and Out_State actually mean? I think In_State means input variable. I just get confused to what actually Out_State means?
An in parameter can be read but not written by the subprogram. in is the default. Prior to Ada 2012, functions were only allowed to have in parameters. The actual parameter is an expression.
An out parameter implies that the previous value is of no interest. The subprogram is expected to write to the parameter. After writing to the parameter, the subprogram can read back what it has written. On exit the actual parameter receives the value written to it (there are complications in this area!). The actual parameter must be a variable.
An in out parameter is like an out parameter except that the previous value is of interest and can be read by the subprogram before assignment. For example,
procedure Add (V : Integer; To : in out Integer; Limited_To : Integer)
is
begin
-- Check that the result wont be too large. This involves reading
-- the initial value of the 'in out' parameter To, which would be
-- wrong if To was a mere 'out' parameter (it would be
-- uninitialized).
if To + V > Limited_To then
To := Limited_To;
else
To := To + V;
end if;
end Add;
Basically, every parameter to a function or procedure has a direction to it. The options are in, out, in out (both), or access. If you don't see one of those, then it defaults to in.
in means data can go into the subroutine from the caller (via the parameter). You are allowed to read from in parameters inside the routine. out means data can come out of the routine that way, and thus you are allowed to assign values to the parameter inside the routine. In general, how the compiler accomplishes the data passing is up to the compiler, which is in accord with Ada's general philosophy of allowing you to specify what you want done, not how you want it done.
access is a special case, and is roughly like putting a "*" in your parameter definition in Cish languages.
The next question folks usually have is "if I pass something large as an in parameter, is it going to push all that data on the stack or something?" The answer is "no", unless your compiler writers are unconsionably stupid. Every Ada compiler I know of under the hood passes objects larger than fit in a machine register by reference. It is the compiler, not the details of your parameter passing mechanisim, that enforces not writing data back out of the routine. Again, you tell Ada what you want done, it figures out the most efficient way to do it.

Resources