Ada 2020 (追記2) - 非互換性

Ada 2020で挙動が変わるコードの考察。 引き続きこのページも妄想でできています。

コンパイルエラーになるもの

予約語

新しい予約語 parallel を使っていた場合はエラーになります。

declare
   type Port_Type is (Serial, Parallel); -- error

識別子の衝突

use または use all type しているライブラリに新しく追加されたエンティティの識別子が衝突する可能性があります。

declare
   package Pkg1 is
      package Stable is
         ZZZ : Integer;
      end Stable;
   end Pkg1;
   package Float_Vectors is new Ada.Containers.Vectors (Positive, Float);
   use Pkg1;
   use Float_Vectors;
   package Alias renames Stable; -- error
   ZZZ : Integer renames Alias.ZZZ;

似たような話では private procedure の仕様部から親パッケージの private with が見えるようになったために衝突する場合もあると思われます。 45日目を参照。

package Lib1 is
   subtype T is Integer;
end Lib1;

package Lib2 is
   subtype T is Float;
end Lib2;

with Lib1;
private with Lib2;
package Parent is
   use Lib1;
private
   use Lib2;
end Parent;

private procedure Parent.Child (Argument : T); -- error

Pureパッケージ内のgeneric内のグローバル変数

Pure パッケージ内にネストされた generic の中でグローバル変数を宣言していた場合エラーになります。 43日目を参照。

既存の処理系でもほぼエラーになっていたと思います。

genericのin引数をrenames

genericin 引数を renames する場合 not null が一致していなかったらエラーになります。 42日目を参照。

ドット記法をrenames

ドット記法を renames していた場合、オブジェクト名部分が renames 不可能だったらエラーになります。 41日目を参照。

抽象型のin式

ユーザー定義の "=" 演算子を持つ抽象型で実体が基本型の場合、実体が可視の箇所からin式を使用しているとエラーになります。 41日目を参照。

抽象型のaccess型の引数を持つプリミティブ

型の本体が tagged 型だった場合 not null が無ければエラーになります。 42日目を参照。

package Pkg2 is
   type T is private;
   procedure Primitive (Object : access T); -- error
private
   type T is tagged null record;
end Pkg2;

Ada 95の頃はこのようなコードは沢山書かれていました。

匿名のaccess型からの暗黙の型変換

匿名の access 型からの暗黙の型変換で生存期間のチェックが行われるようになったため違反していればエラーになります。 42日目を参照。

record内の匿名のaccess型

record 内の匿名の access 型が外側の recordConvention を引き継ぐようになりましたのでデフォルトの Convention => Ada を期待していた箇所でエラーになります。 42日目を参照。

declare
   type T is
      record
         Callback : not null access procedure;
      end record
        with Convention => Fortran;
   procedure Ada_Proc is null;
   Item : T := (Callback => Ada_Proc'Access); -- error

protected内の匿名のaccess型

protected 内の匿名の access procedure 型が access protected procedure ではなく他と同じになりましたので access protected procedure を期待していた箇所でエラーになります。 42日目を参照。

declare
   protected Prot1 is
      procedure High_Order (Callback : not null access procedure);
   end Prot1;
   protected Prot2 is
      procedure Callback;
   end Prot2;
   -- Prot1とProt2の実装は省略
begin
   Prot1.High_Order (Prot2.Callback'Access); -- error

protected を書き足す必要があります。

protected内のデフォルト引数

protected 内のデフォルト引数や事前条件で内部呼び出しを行っていた場合エラーになります。 39日目を参照。

protectedとclass-wideアスペクト

protected 内でclass-wideアスペクトを指定していたらエラーになります。 39日目を参照。

アスペクト

自己参照していたらエラーになります。 45日目を参照。

抽象型に内部表現が指定されていたらエラーになります。 45日目を参照。

Constant_Indexing/Variable_Indexing

片方だけ指定しておいて派生先でもう片方を指定したり、interface に指定しておいて派生先で衝突したりすればエラーになります。 41日目を参照。

Ada 2012からあるアスペクトでは Default_IteratorImplicit_DereferenceIterator_Element も同様です。

Remote_Call_Interface

‘Read/’Write 属性をユーザー定義していたらエラーになります。 45日目を参照。

pragma Conflict_Check_Policy

Ada 2020では変数へのアクセスの競合がコンパイル時にチェックされます。 18日目を参照。

私の探し方が悪いのかpragma Conflict_Check_Policy のデフォルトを見つけられませんでした。 恐らく処理系のスイッチで変えられるようになるとは思います。

そうしますと、処理系の設定次第でこれまで通っていたコードがエラーになる可能性があります。 実際には問題のないコードの場合は pragma Conflict_Check_Policy (No_Tasking_Conflict_Checks); を書き足して回避できます。

pragma Task_Dispatching_Policy (EDF_Across_Priorities)

EDF_Across_PrioritiesEDF_Within_Priorities に変わりました。 挙動も絶対時刻メインから相対時刻メインへと変更されています。 31日目を参照。

pragma Restrictions (No_IO)

No_IOAda.Directories が含まれるようになりましたので No_IO を指定していながら Ada.Directories を使っているコードがエラーになります。 33日目を参照。

挙動が変わるもの

universal_integerの範囲エラー

実行時にuniversal_integerがroot_integerの範囲を超えたら Constraint_Error になります。 44日目を参照。

universal_realも同様にroot_realの範囲を超えたら Constraint_Error になります。

Unchecked_Unionのin式

unconstrained in unconstrained | constrainedの形の式があった場合評価順に関わらず Program_Error になるようになりました。 41日目を参照。

protectedの遅延初期化

protected 型の要素に遅延初期化のルールが適用されるようになりましたので初期化順が変わるかもしれません。 40日目を参照。

requeue文とAccessibility_Check

requeue 文で実行時に Accessibility_Check が行われるようになったため偶々クラッシュ等せずに運良く動いていたコードが実行時エラーになるかもしれません。 38日目を参照。

predicateのチェックタイミング

デフォルト初期化でもpredicateがチェックされるようになりましたので Default_Value とpredicateが矛盾していたのを見逃されていたコードがあれば実行時エラーになるかもしれません。 38日目を参照。

また未初期化変数を out パラメータに渡した場合にはpredicateもチェックされなくなりましたので例外の発生を期待していたコードがあれば挙動が変わるかもしれません。 (無いだろjk。)

pragma Assertion_Policy

pragma Assertion_Policy が標準ライブラリの中まで影響を及ぼさなくなりましたのでこれまで抑制できていたチェックが抑制できなくなって挙動が変わるかもしれません。 37日目を参照。

pragma Restrictions (No_Dynamic_Attachment)

No_Dynamic_Attachment を指定していた場合同じ割り込み番号に複数のハンドラがあると Program_Error になります。 33日目を参照。

処理系依存のもの

文字列の正規化

もしソースコードをNFKC正規化していた処理系であれば、文字列に許されている正規化がNFKCからNFCに変わったことでコンパイル結果の文字列が変化するかもしれません。 34日目を参照。 (そのような処理系が実在するかは不明です。)

begin
   Ada.Wide_Wide_Text_IO.Put ("㍉");

今まで ミリ が出力されていた処理系でもAda 2020からは になります。

挙動が決まっていなかったケース

決まっていなかった挙動がAda 2020で定められた中で、処理系のこれまでの挙動がAda 2020と異なっていた場合は挙動が変わることになります。

Ada.Directories.Containing_Directory ("/") あたりが危険そうです。

注意

Ada 2012 with Technical Corrigendum 1の変更は含めていません。

Technical Corrigendum 1でも契約関連で大きく修正されたり Pure 内でvariable viewを持つ constant が禁止されたりと結構大きな非互換がありますので見ておくといいと思います。

例によってJohn Barnes先生の Rationale Update for Ada 2012 に良くまとまっています。