Ada 源于未检查的联合

Ada 源于未检查的联合,ada,gnat,Ada,Gnat,我声明的联合类型如下: type Access_Kind is (Named, Indexed); type Array_Type is array (0 .. 1) of Integer; type Record_Type (Kind : Access_Kind := Access_Kind'First) is record case Kind is when Named => X, Y : Integer; when Indexed =

我声明的联合类型如下:

type Access_Kind is (Named, Indexed);
type Array_Type is array (0 .. 1) of Integer;

type Record_Type (Kind : Access_Kind := Access_Kind'First) is record
   case Kind is
      when Named =>
         X, Y : Integer;
      when Indexed =>
         S : Array_Type;
   end case;
end record;
pragma Unchecked_Union (Record_Type);
pragma Convention (C_Pass_By_Copy, Record_Type);

function Create (X, Y : Integer) return Record_Type;
现在,当我尝试创建派生类型时:

type Integer2 is new Record_Type;
GNAT给了我以下警告:

warning: in instantiation at line [pragma Convention...]
warning: variant record has no direct equivalent in C
warning: use of convention for type "Integer2" is dubious
因此,看起来pragma约定应用于派生类型,但未选中的联合不是。我无法将其再次应用于派生类型,因为
Record\u type
已经定义了基本操作(
Integer2
在另一个包中定义)

这是正确的行为还是蚊虫?如何正确地从未检查的\u Union类型派生,以便新类型继承未检查的\u Union pragma

GNAT版本:GNAT GPL 2012(20120509)。

在Ada 2012中已过时,您现在可以指定方面。在这两种情况下,如中所述,警告提醒人们,未经检查的联合类型“在Ada 2005中引入的唯一目的是与C程序接口,而不是危险地生活。”不禁止从
记录类型派生的类型;这只是一个坏主意,因为它传播了错误执行的机会,如本节所示。相反,将联合封装在绑定体中,并从更高级别的类型派生

附录:检查旧版本以供参考

GNAT 4.6 Copyright 1996-2010, Free Software Foundation, Inc. ... Representation information for unit Unchecked (body) ---------------------------------------------------- for Array_Type'Size use 64; for Array_Type'Alignment use 4; for Array_Type'Component_Size use 32; for Record_Type'Size use 64; for Record_Type'Alignment use 4; for Record_Type use record Kind at ?? range 0 .. -1; X at 0 range 0 .. 31; Y at 4 range 0 .. 31; S at 0 range 0 .. 63; end record; for Integer2'Size use 96; for Integer2'Alignment use 4; for Integer2 use record Kind at 0 range 0 .. 7; X at 4 range 0 .. 31; Y at 8 range 0 .. 31; S at 4 range 0 .. 63; end record; 蚊虫4.6 版权所有,1996年至2010年,自由软件基金会。 ... 未选中单元的表示信息(主体) ---------------------------------------------------- 对于数组_类型的大小,使用64; 对于数组_类型的对齐,使用4; 对于数组类型“组件大小”使用32; 对于记录类型“大小”使用64; 对于“校准”类型的记录,使用4; 对于记录类型,请使用记录 种类在??范围0-1. 0范围内的X。。31; Y在4范围0。。31; S在0范围0。。63; 结束记录; 对于整数2’大小,使用96; 对于整数2'对齐,使用4; 对于整数2,请使用记录 种类在0范围0。。7. X在4范围内0。。31; Y在8范围0。。31; S在4范围0。。63; 结束记录; 在Ada 2012中,已过时,现在可以指定方面。在这两种情况下,如中所述,警告提醒人们,未经检查的联合类型“在Ada 2005中引入的唯一目的是与C程序接口,而不是危险地生活。”不禁止从
记录类型派生的类型;这只是一个坏主意,因为它传播了错误执行的机会,如本节所示。相反,将联合封装在绑定体中,并从更高级别的类型派生

附录:检查旧版本以供参考

GNAT 4.6 Copyright 1996-2010, Free Software Foundation, Inc. ... Representation information for unit Unchecked (body) ---------------------------------------------------- for Array_Type'Size use 64; for Array_Type'Alignment use 4; for Array_Type'Component_Size use 32; for Record_Type'Size use 64; for Record_Type'Alignment use 4; for Record_Type use record Kind at ?? range 0 .. -1; X at 0 range 0 .. 31; Y at 4 range 0 .. 31; S at 0 range 0 .. 63; end record; for Integer2'Size use 96; for Integer2'Alignment use 4; for Integer2 use record Kind at 0 range 0 .. 7; X at 4 range 0 .. 31; Y at 8 range 0 .. 31; S at 4 range 0 .. 63; end record; 蚊虫4.6 版权所有,1996年至2010年,自由软件基金会。 ... 未选中单元的表示信息(主体) ---------------------------------------------------- 对于数组_类型的大小,使用64; 对于数组_类型的对齐,使用4; 对于数组类型“组件大小”使用32; 对于记录类型“大小”使用64; 对于“校准”类型的记录,使用4; 对于记录类型,请使用记录 种类在??范围0-1. 0范围内的X。。31; Y在4范围0。。31; S在0范围0。。63; 结束记录; 对于整数2’大小,使用96; 对于整数2'对齐,使用4; 对于整数2,请使用记录 种类在0范围0。。7. X在4范围内0。。31; Y在8范围0。。31; S在4范围0。。63; 结束记录;
一种可能是在嵌套包中声明
Record\u Type
的操作,例如
Ops
,这样它们就不是原始的:

package Union is

   type Access_Kind is (Named, Indexed);
   type Array_Type is array (0 .. 1) of Integer;

   type Record_Type (Kind : Access_Kind := Access_Kind'First) is record
      case Kind is
         when Named =>
            X, Y : Integer;
         when Indexed =>
            S : Array_Type;
      end case;
   end record;
   pragma Unchecked_Union (Record_Type);
   pragma Convention (C_Pass_By_Copy, Record_Type);

   --  If P was declared immediately within Union, it would be
   --  primitive, and it wouldn't be possible to declare
   --  representation aspects for Integer2.
   package Ops is
      procedure P (R : Record_Type) is null;
      --  "is null" only so that I can use -gnatR without needing a
      --  body.
   end Ops;

   type Integer2 is new Record_Type;
   pragma Unchecked_Union (Integer2);
   pragma Convention (C_Pass_By_Copy, Integer2);

end Union;
使用
-gnatR
显示所选的表示,我得到

$ gnatmake -c -u -f -gnatwa union.ads -gnatR
gcc -c -gnatwa -gnatR -gnat05 union.ads

Representation information for unit Union (spec)
------------------------------------------------

for Array_Type'Size use 64;
for Array_Type'Alignment use 4;
for Array_Type'Component_Size use 32;

for Record_Type'Size use 64;
for Record_Type'Alignment use 4;
for Record_Type use record
   Kind at ?? range  0 ..  -1;
   X    at  0 range  0 .. 31;
   Y    at  4 range  0 .. 31;
   S    at  0 range  0 .. 63;
end record;

for Integer2'Size use 64;
for Integer2'Alignment use 4;
for Integer2 use record
   Kind at ?? range  0 ..  -1;
   X    at  0 range  0 .. 31;
   Y    at  4 range  0 .. 31;
   S    at  0 range  0 .. 63;
end record;
也就是说,我认为GNAT的行为是错误的

表示有代表性方面和操作性方面,并定义了代表性方面。这就是为什么我们需要避免原始操作。表示表征方面由派生类型继承;但表示操作方面是而不是,“除非为特定方面指定”。我猜“指定”是指“在ARM中用于语言定义的方面,或由供应商用于供应商定义的方面”

声明
未选中\u Union
是一个表示方面。因此,它应该被继承

说明接口方面,包括
约定
,是表示方面<因此,应继承代码>按副本传递


我会准备一份bug报告。

一种可能是在嵌套包中声明
记录类型的操作,比如
Ops
,这样它们就不是原始的:

package Union is

   type Access_Kind is (Named, Indexed);
   type Array_Type is array (0 .. 1) of Integer;

   type Record_Type (Kind : Access_Kind := Access_Kind'First) is record
      case Kind is
         when Named =>
            X, Y : Integer;
         when Indexed =>
            S : Array_Type;
      end case;
   end record;
   pragma Unchecked_Union (Record_Type);
   pragma Convention (C_Pass_By_Copy, Record_Type);

   --  If P was declared immediately within Union, it would be
   --  primitive, and it wouldn't be possible to declare
   --  representation aspects for Integer2.
   package Ops is
      procedure P (R : Record_Type) is null;
      --  "is null" only so that I can use -gnatR without needing a
      --  body.
   end Ops;

   type Integer2 is new Record_Type;
   pragma Unchecked_Union (Integer2);
   pragma Convention (C_Pass_By_Copy, Integer2);

end Union;
使用
-gnatR
显示所选的表示,我得到

$ gnatmake -c -u -f -gnatwa union.ads -gnatR
gcc -c -gnatwa -gnatR -gnat05 union.ads

Representation information for unit Union (spec)
------------------------------------------------

for Array_Type'Size use 64;
for Array_Type'Alignment use 4;
for Array_Type'Component_Size use 32;

for Record_Type'Size use 64;
for Record_Type'Alignment use 4;
for Record_Type use record
   Kind at ?? range  0 ..  -1;
   X    at  0 range  0 .. 31;
   Y    at  4 range  0 .. 31;
   S    at  0 range  0 .. 63;
end record;

for Integer2'Size use 64;
for Integer2'Alignment use 4;
for Integer2 use record
   Kind at ?? range  0 ..  -1;
   X    at  0 range  0 .. 31;
   Y    at  4 range  0 .. 31;
   S    at  0 range  0 .. 63;
end record;
也就是说,我认为GNAT的行为是错误的

表示有代表性方面和操作性方面,并定义了代表性方面。这就是为什么我们需要避免原始操作。表示表征方面由派生类型继承;但表示操作方面是而不是,“除非为特定方面指定”。我猜“指定”是指“在ARM中用于语言定义的方面,或由供应商用于供应商定义的方面”

声明
未选中\u Union
是一个表示方面。因此,它应该被继承

说明接口方面,包括
约定
,是表示方面<因此,应继承代码>按副本传递


我会准备一份bug报告。

虽然你的陈述是正确的,但这并不能回答我的问题。除了警告之外,我还有其他证据证明派生类型不是未检查的联合(最小类型大小包括判别大小),所以我仍然想知道为什么不是这种情况,以及如何解决这个问题。顺便说一句,在这种情况下,上述错误执行是不可能的,因为两个变量包含相同的类型,因此不能用于未经检查的转换;这是一个Ada变体记录,在C中没有直接的等价物;此外,
C\u Pass\u By\u Copy
对于具有该类型的参数没有意义。对不起,如果我