TamaMcGlinn
TamaMcGlinn

Reputation: 3248

Why does GNAT reject an array type with a default discriminant value?

This (declaration) code raises a storage error:

type Vector is array (Integer range <>) of Integer;
type Array_Starting_At_One (Max : Integer := 0) is
   record
      Mat : Vector (1 .. Max);
   end record;

X : Array_Starting_At_One;

I can't figure out why. If I specify the default, as in X : Array_Starting_At_One (Max => 0); the error disappears, although the Array_Starting_At_One type specification still triggers a warning that creation of such objects may raise Storage_Error.

I am not even trying to store a single bit, so this error doesn't make any sense to me:

raised STORAGE_ERROR : System.Memory.Alloc: object too large

Upvotes: 5

Views: 290

Answers (3)

Jeffrey R. Carter
Jeffrey R. Carter

Reputation: 3358

As you notice, this is a compiler issue. The Janus/Ada compiler would accept your code without complaint or run-time exception.

Your variable X is an unconstrained object; the discriminant (and so the size of the object) can be changed by full-record assignment. The ARM is silent about how such things should be implemented. GNAT has chosen to allocate enough space for the largest possible value; since X is allocated on the stack, there will not be enough space for it with GNAT's default stack size (if you allocate it on the heap, you might not have a problem). Janus instead allocates only enough space for the current value, which may result in X.Mat being implicitly allocated on the heap.

The Janus way is more developer-friendly and acceptable for most applications, where the developer doesn't care where things are allocated, but there are situations where implicit heap allocation cannot be accepted, so the GNAT way is more general.

Upvotes: 3

egilhh
egilhh

Reputation: 6430

When a variable is declared using the default discriminant, then the discriminant can later be changed via an assignment. This means that the compiler (at least GNAT does this) will allocate (on the stack) enough room to hold an object with any discriminant up to the maximum allowed value (Integer'Last in this case).

Either increase your stack size (not neccessarily recommended), or use a different subtype more suited to your problem:

subtype Foo is Integer range 1..10;
type Vector is array (Foo range <>) of Integer;

Upvotes: 5

Jim Rogers
Jim Rogers

Reputation: 5021

Certainly any array with an index range of 1..Integer'Last could raise Storage_Error. The compiler is warning you of this possibility. Try restricting the index range for your array type such as:

subtype Indices is Integer range 0..1024;
type Vector is Array (Indices range <>) of Integer;
type Array_Ending_At (Max : Indices := 0) is
   record
      Mat : Vector(1..Max);
   end record;

Upvotes: 5

Related Questions