John Leimon
John Leimon

Reputation: 1091

Ada: Violation of "No_Exception_Propagation" - Part 2

I have the following code which combines two bytes into a byte array:

pragma Restrictions (No_Exception_Propagation);

with Interfaces; use Interfaces;

procedure No_Propagation is
   type Byte is new Unsigned_8;
   type Byte_Array is array (Natural range <>) of Byte;

   function Concat (Input_1 : Byte;
                    Input_2 : Byte)
                    return Byte_Array
   is
      Null_Array : Byte_Array (1 .. 0);
   begin
      declare
         Output : constant Byte_Array := Byte_Array'(Input_1 & Input_2);
      begin
         return Output;
      exception
         when Constraint_Error =>
            return Null_Array;
      end;
   end Concat;

   A, B : Byte;
begin
   A := 5;
   B := 0;
   declare
      C : Byte_Array := Concat(A, B);
   begin
      null;
   end;
end No_Propagation;

When I compile this with:

gnatmake -gnatw.e no_propagation.adb

I get the following warning:

no_propagation.adb:16:66: warning: pragma Restrictions (No_Exception_Propagation) in effect
no_propagation.adb:16:66: warning: "Constraint_Error" may result in unhandled exception

Q1. Why am I getting a warning that a "Constraint_Error" may result in an unhandled exception when I have an exception handler in the declare block within the Concat function?

Q2. How could pasting two bytes together into a Byte_Array generate a Constraint Error?

Upvotes: 2

Views: 268

Answers (2)

Simon Wright
Simon Wright

Reputation: 25491

I think your code is triggering an over-enthusiastic warning from GNAT.

To answer question 1, you will see a little further down

no_propagation.adb:20:10: warning: pragma Restrictions (No_Exception_Propagation) in effect
no_propagation.adb:20:10: warning: this handler can never be entered, and has been removed

and the reason for this is that your exception handler is too late, as @BrianDrummond suggested. You write

  declare
     Output : constant Byte_Array := Byte_Array'(Input_1 & Input_2);
  begin
     return Output;
  exception
     when Constraint_Error =>
        return Null_Array;
  end;

and if any exception were to occur it would have to be in the declarative region, which is not covered by that handler. You could try to write instead

      declare
         Output : constant Byte_Array := Byte_Array'(Input_1 & Input_2);
      begin
         return Output;
      end;
   exception
      when Constraint_Error =>
         return Null_Array;

but you would get the same warning; this time, I think, because the exception would need to be propagated out of the scope in which it was raised. If so, this seems to be an unfortunate consequence of the rules, or possibly an implementation issue: No_Exception_Propagation is a GNAT extension,

This restriction guarantees that exceptions are never propagated to an outer subprogram scope. The only case in which an exception may be raised is when the handler is statically in the same subprogram, so that the effect of a raise is essentially like a goto statement. Any other raise statement (implicit or explicit) will be considered unhandled. Exception handlers are allowed, but may not contain an exception occurrence identifier (exception choice). In addition, use of the package GNAT.Current_Exception is not permitted, and reraise statements (raise with no operand) are not permitted.

As for question 2, this looks like another compiler issue. Byte_Array’(Input_1 & Input_2) causes the warning, Byte_Array'(Input_1, Input_2) doesn’t.

In either case, you get the same warning on the call to Concat.

The best approach is probably to suppress all of these warnings using -gnatw.X, "turn off warnings for non-local exception" (this is supposed to be the default, but I guess the warnings get turned on with No_Exception_Propagation).

Upvotes: 3

Jim Rogers
Jim Rogers

Reputation: 5021

A much simpler version of your program is:

------------------------------------------------------------------
-- Simpler version of no propogation --
------------------------------------------------------------------
pragma Restrictions (No_Exception_Propagation);

with Interfaces; use Interfaces;

procedure No_Propagation2 is
   type Byte is new Unsigned_8;
   type Byte_Array is array (Natural range <>) of Byte;

   function Concat (Input_1 : Byte;
                    Input_2 : Byte)
                    return Byte_Array
   is
   begin
      return (Input_1, Input_2);
   end Concat;

   A : Byte := 5;
   B : Byte := 0;
   C : Byte_Array := Concat(A, B);
begin
   null;
end No_Propagation2;

Upvotes: 3

Related Questions