Ada 在编译时确保异常覆盖率

Ada 在编译时确保异常覆盖率,ada,Ada,有没有办法让GNAT确保所有异常情况都得到处理 举个例子: package IO renames Ada.Text_IO; package EIO renames Ada.IO_Exceptions; procedure Open_File (File : in out IO.File_Type) is begin IO.Open (File, IO.In_File, "example.txt"); exception

有没有办法让GNAT确保所有异常情况都得到处理

举个例子:

   package IO renames Ada.Text_IO;
   package EIO renames Ada.IO_Exceptions;

   procedure Open_File (File : in out IO.File_Type) is
   begin
      IO.Open (File, IO.In_File, "example.txt");
   exception
      when EIO.Use_Error =>
         IO.Put_Line ("Use!");
      when EIO.Device_Error =>
         IO.Put_Line ("Device!");
   end Open_File;
Open
还可能引发
Name\u错误
,因此我想提醒GNAT案件尚未处理

我发现
pragma限制(无异常传播)
但这似乎也将检查应用于标准库调用,因此
Open
变得不可用,因为它本身传播异常。如果我将此应用于我的示例,我会得到:

14:07: warning: pragma Restrictions (No_Exception_Propagation) in effect
14:07: warning: this handler can never be entered, and has been removed
16:07: warning: pragma Restrictions (No_Exception_Propagation) in effect
16:07: warning: this handler can never be entered, and has been removed

举例说明我想从另一种语言中得到什么;Nim有一个
raises
pragma来注释一个过程可以引发哪些异常,这些异常由编译器强制执行。列表可以为空,即,
引发:[]
,编译器将要求处理所有异常,而不是传播。Ada中是否有与此等效的程序?

如果您想处理所有可用的异常,可以在
异常
部分中的其他异常时使用
。您的示例如下所示:

package IO renames Ada.Text_IO;
package EIO renames Ada.IO_Exceptions;

procedure Open_File (File : in out IO.File_Type) is
begin
   IO.Open (File, IO.In_File, "example.txt");
exception
   when An_Exception : others =>
      IO.Put_Line (EIO.Exception_Message(An_Exception));
end Open_File;

如果希望以单独的方式处理每个异常,那么必须单独列出每个异常(如示例中所示)。但编译器不会警告您缺少异常处理程序。

这在Ada中是不可能的

Nim之所以能够做到这一点,是因为
引发的杂注是函数签名的一部分。因此,对于任何调用,静态地知道可以引发哪些异常。Ada的情况并非如此


如果您认为编译器可以隐式地找出任何子例程可以引发哪些异常,这是正确的,但并不能解决问题,因为Ada同时允许调度调用和函数指针。对于这两种情况,您都无法静态地知道将调用的函数(没有指针分析,这超出了大多数编译器的范围),因此无法知道可能引发的异常(因为它们不是签名的一部分)。

使用SPARK,通过证明不会引发任何异常,您可以保证所有异常都在程序的SPARK verified部分中得到处理……编译器无法确定会引发哪些异常。c.l.a.的一位撰稿人指出,
Storage\u Error
总是有可能被引发的(例如,通过堆栈溢出,我怀疑SPARK也能阻止它)@SimonWright,这只意味着编译器告诉您,任何分配数据的操作都可以引发
Storage\u Error
(就像任何除法运算都可能产生约束错误一样)。这更多的是一种理论上的评论;Ada的模块化编译模型禁止传播这种源于身体的知识,因为编译单元只知道其他单元的规范。有语言(例如Zig)这确实将
存储错误
视为一个推断错误和签名的一部分。不必是分配,至少不必是从堆中:如果您声明一个长度为
整数的字符串'Last
,那么获得
存储错误
将是令人高兴的,而不是一个非常模糊的内存破坏。类似的情况会发生因为我认为
Unchecked\u转换
只提供了对象的备用视图,而不是在堆栈上创建副本(此行为可能受优化级别的影响)