Skip to content

[feature] Allow use of discriminants of unchecked unions in non-executable ghost code #202

Description

@clairedross

Summary

We want it to be possible to mention the discriminants of record type with the Unchecked_Union aspect inside ghost code whose assertion level depends on Static. The syntax and semantics would be exactly the same as for other references to discriminants. The fact that the discriminant is not represented in practice is not a problem as the code cannot be enabled at runtime.

It would also be interesting to state that the expected semantics of predefined equality on Unchecked_Union types is not to raise Program_Error when called inside such a context. It does not change much for execution, as this will never be executed, but it has an impact for static analysis.

   type My_Rec (Is_Int : Boolean := False) is record
      case Is_Int is
         when True =>
            F_Int : Integer;
         when False =>
            F_Float : Float;
      end case;
   end record with
     Unchecked_Union;
   
   function Read_F_Int (X : My_Rec) return Integer with
     Pre => (Static => X.Is_Int);
   
   function Read_F_Int (X : My_Rec) return Integer is (X.F_Int);
   
   procedure Write_F_Int_If_B (X : in out My_Rec; B : Boolean) with
     Post => (Static => (if B then X = (True, 12) else X = X'Old));
   
   procedure Write_F_Int_If_B (X : in out My_Rec; B : Boolean) is
   begin
      if B then
         X := (True, 12);
      end if;
   end Write_F_Int_If_B;

Motivation

Unchecked unions are currently badly handled in SPARK. As per Ada semantics, it is necessary to track the value of the discriminants of such objects, as the fields should only be accessed when the discriminants allow it. However, as these discriminants do not actually occur in the object, they cannot be mentioned. This is a major issue because it prevents users from writing contracts that mention them. As a result, it is not possible to have a verified subprogram that accesses a component of an object of an unchecked union type that it takes as a parameter or accesses globally.

Caveats and alternatives

This actually changes the semantics of Ada, at least inside non-executable contracts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions