Fellow Teamers -

I am working on a large (>1M SLOC) Ada95 project.  We are applying static analysis to help identify and remove sources of operational instability.  Our analysis has revealed numerous use-before-set problems.  Many of the problems are simple programming errors, but there are several pervasive problems which are not easily solved.  The reason is that the problems are related to parameter profiles for generics and access to subprogram types (callbacks), as will be illustrated shortly.  I need to understand which of these problems are near-term, must fix problems, and which can be worked later.  To that end, I would appreciate your insights on the language.  I have to say,  in over an hour of digging in the LRM I was unable to find a definitive statement.  Okay, on to the code.

> The first problem category is passing uninitialized variables to subprograms with "in out" parameters.  This is a potential problem if, inside the subprogram, the parameter is read before being set.  However, exceptions can still arise even if the parameter is not read.  Consider the following example:
>
> procedure Main2 is
>
>    type Color is (Red, Green);
>
>    procedure Initialize (P : in out Color) is
>    begin
>       P := Green;
>    end;
>
>    Var : Color;
>    Tar : Color range Red..Red;
>    Car : Color range Green..Green;
>
> begin
>
>    Initialize(Var);  -- GNAT 3.13p Does not raise exception
>    Initialize(Car);  -- GNAT 3.13p Raises Constraint_Error
>    Initialize(Tar);  -- GNAT 3.13p Raises Constraint_Error
>
> end;
>
Testing revealed no exceptions with pass-by-reference parameters. I need to understand when is this simply awful but unexceptional code, and when is it prone to exceptions.  In particular, can the first call  potentially raise exceptions on some other implementation?  RM 3.2.2(12) suggests why a pass-by-copy parameter could raise an exception, but then why don't all three calls raise Constraint_Error?  Are pass-by-reference parameters always immune to exceptions under these conditions?

> The second category of problems is failure to assign a value to an "out" parameter.  This is certainly a problem if the caller should try to use the result.  However, exceptions can still arise even if the parameter is not used.  Consider another example:
>
> procedure Main is
>
>    type Color is (Red, Green);
>
>    procedure Is_Broken (P : out Color) is
>    begin
>       null;
>    end;
>
>    Var : Color;
>    Tar : Color range Red..Red;
>    Car : Color range Green..Green;
>
> begin
>
>    Is_Broken(Var);  -- Does not raise exception
>    Is_Broken(Tar);  -- Does not raise exception
>    Is_Broken(Car);  -- Raises Constraint_Error
>
> end;
>
> The obvious solution is to always assign a value to the parameter, but this may not always be possible.  For example, we have generic containers with methods that can return a component and a validity flag.  If a component can not be returned, the container assigns nothing to the component parameter, and sets the validity parameter appropriately.  Unfortunately, the containers have no formal nil object in there specification, and therefor cannot return a safe value.  Again, to change a generic spec. can have significant ripple effect on other units.
>
Thanks in advance for your comments,

        - John Harbaugh