* Unexpected discriminant check failure involving access types
@ 2015-08-10 12:38 Markus Schöpflin
2015-08-10 13:14 ` Mark Lorenzen
2015-08-10 14:33 ` Niklas Holsti
0 siblings, 2 replies; 7+ messages in thread
From: Markus Schöpflin @ 2015-08-10 12:38 UTC (permalink / raw)
Given the following piece of code:
---%<---
1 procedure TEST
2 is
3 type T is (T1, T2);
4
5 type RECORD_T (X : T := T1) is record
6 null;
7 end record;
8
9 type PTR_T is access RECORD_T;
10
11 FOO : RECORD_T;
12 FOO_PTR : constant PTR_T := new RECORD_T;
13
14 FOO1 : constant RECORD_T := (X => T1);
15 FOO2 : constant RECORD_T := (X => T2);
16 begin
17 FOO := FOO1;
18 FOO := FOO2;
19
20 FOO_PTR.all := FOO1;
21 FOO_PTR.all := FOO2;
22 end;
--->%---
When compiled and executed, I get:
> ./test
raised CONSTRAINT_ERROR : test.adb:21 discriminant check failed
Can anyone please explain me why I get a discriminant check error when using
access types? I would have expected it to work the same as for the non-access
case.
TIA, Markus
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Unexpected discriminant check failure involving access types
2015-08-10 12:38 Unexpected discriminant check failure involving access types Markus Schöpflin
@ 2015-08-10 13:14 ` Mark Lorenzen
2015-08-10 14:20 ` Markus Schöpflin
2015-08-10 14:33 ` Niklas Holsti
1 sibling, 1 reply; 7+ messages in thread
From: Mark Lorenzen @ 2015-08-10 13:14 UTC (permalink / raw)
On Monday, August 10, 2015 at 2:38:23 PM UTC+2, Markus Schöpflin wrote:
> Given the following piece of code:
>
> ---%<---
> 1 procedure TEST
> 2 is
> 3 type T is (T1, T2);
> 4
> 5 type RECORD_T (X : T := T1) is record
> 6 null;
> 7 end record;
> 8
> 9 type PTR_T is access RECORD_T;
> 10
> 11 FOO : RECORD_T;
> 12 FOO_PTR : constant PTR_T := new RECORD_T;
> 13
> 14 FOO1 : constant RECORD_T := (X => T1);
> 15 FOO2 : constant RECORD_T := (X => T2);
> 16 begin
> 17 FOO := FOO1;
> 18 FOO := FOO2;
> 19
> 20 FOO_PTR.all := FOO1;
> 21 FOO_PTR.all := FOO2;
> 22 end;
> --->%---
>
> When compiled and executed, I get:
>
> > ./test
>
> raised CONSTRAINT_ERROR : test.adb:21 discriminant check failed
>
> Can anyone please explain me why I get a discriminant check error when using
> access types? I would have expected it to work the same as for the non-access
> case.
>
> TIA, Markus
Look at line 12. FOO_PTR is a constant object of an access type. The constant object is initialized to point to a discriminated record with discriminant T1, since this is the default discriminant of objects of type RECORD_T. In line 21 it goes horribly wrong and you try to change the object pointed to, to a record with discriminant T2.
What problem are you trying to solve? Is the above code just a simple reproducer or is it a snippet from real code?
Regards,
Mark L
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Unexpected discriminant check failure involving access types
2015-08-10 13:14 ` Mark Lorenzen
@ 2015-08-10 14:20 ` Markus Schöpflin
2015-08-10 19:00 ` Randy Brukardt
0 siblings, 1 reply; 7+ messages in thread
From: Markus Schöpflin @ 2015-08-10 14:20 UTC (permalink / raw)
Am 10.08.2015 um 15:14 schrieb Mark Lorenzen:
> On Monday, August 10, 2015 at 2:38:23 PM UTC+2, Markus Schöpflin wrote:
>> Given the following piece of code:
>>
>> ---%<---
>> 1 procedure TEST
>> 2 is
>> 3 type T is (T1, T2);
>> 4
>> 5 type RECORD_T (X : T := T1) is record
>> 6 null;
>> 7 end record;
>> 8
>> 9 type PTR_T is access RECORD_T;
>> 10
>> 11 FOO : RECORD_T;
>> 12 FOO_PTR : constant PTR_T := new RECORD_T;
>> 13
>> 14 FOO1 : constant RECORD_T := (X => T1);
>> 15 FOO2 : constant RECORD_T := (X => T2);
>> 16 begin
>> 17 FOO := FOO1;
>> 18 FOO := FOO2;
>> 19
>> 20 FOO_PTR.all := FOO1;
>> 21 FOO_PTR.all := FOO2;
>> 22 end;
>> --->%---
>>
>> When compiled and executed, I get:
>>
>> > ./test
>>
>> raised CONSTRAINT_ERROR : test.adb:21 discriminant check failed
>>
>> Can anyone please explain me why I get a discriminant check error when using
>> access types? I would have expected it to work the same as for the non-access
>> case.
>>
>> TIA, Markus
>
> Look at line 12. FOO_PTR is a constant object of an access type. The
> constant object is initialized to point to a discriminated record with
> discriminant T1, since this is the default discriminant of objects of type
> RECORD_T. In line 21 it goes horribly wrong and you try to change the
> object pointed to, to a record with discriminant T2.
I still don't get it: I would have expected the objects FOO and
FOO_PTR.all to be identical in behaviour. Why is "new RECORD_T" creating a
constrained record and just using "RECORD_T" not?
> What problem are you trying to solve? Is the above code just a simple
> reproducer or is it a snippet from real code?
That is a reproducer for a bug found in some real code, which suddenly started
to give constraint errors, due to a change in the initialization of a variable
of type PTR_T.
Markus
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Unexpected discriminant check failure involving access types
2015-08-10 12:38 Unexpected discriminant check failure involving access types Markus Schöpflin
2015-08-10 13:14 ` Mark Lorenzen
@ 2015-08-10 14:33 ` Niklas Holsti
2015-08-10 14:56 ` Markus Schöpflin
1 sibling, 1 reply; 7+ messages in thread
From: Niklas Holsti @ 2015-08-10 14:33 UTC (permalink / raw)
On 15-08-10 15:38 , Markus Schöpflin wrote:
> Given the following piece of code:
>
> ---%<---
> 1 procedure TEST
> 2 is
> 3 type T is (T1, T2);
> 4
> 5 type RECORD_T (X : T := T1) is record
> 6 null;
> 7 end record;
> 8
> 9 type PTR_T is access RECORD_T;
> 10
> 11 FOO : RECORD_T;
> 12 FOO_PTR : constant PTR_T := new RECORD_T;
> 13
> 14 FOO1 : constant RECORD_T := (X => T1);
> 15 FOO2 : constant RECORD_T := (X => T2);
> 16 begin
> 17 FOO := FOO1;
> 18 FOO := FOO2;
> 19
> 20 FOO_PTR.all := FOO1;
> 21 FOO_PTR.all := FOO2;
> 22 end;
> --->%---
>
> When compiled and executed, I get:
>
> > ./test
>
> raised CONSTRAINT_ERROR : test.adb:21 discriminant check failed
>
> Can anyone please explain me why I get a discriminant check error when
> using access types? I would have expected it to work the same as for the
> non-access case.
This is a consequence of RM 4.8(6/3): "... If the designated type is
composite, then the subtype of the created object is the designated
subtype when the designated subtype is constrained or there is an
ancestor of the designated type that has a constrained partial view;
otherwise, the created object is constrained by its initial value (even
if the designated subtype is unconstrained with defaults)."
In other words, the object FOO_PTR.all is constrained and it is not
possible to change its discriminants -- the default value given to the
discriminant X, which means that FOO is unconstrained, does not have the
same effect on an allocated object.
The AARM motivates this rule as follows: "All objects created by an
allocator are aliased, and most aliased composite objects need to be
constrained so that access subtypes work reasonably." In other words,
there could be a declarations like
type PTR_T1_T is access all RECORD_T (X => T1);
FOO_T1_PTR : PTR_T1_T;
and statements
FOO_T1_PTR := PTR_T1_T (FOO_PTR);
Now FOO_PTR and FOO_T1_PTR point to the same object (the allocated one),
with X = T1. If the program could now change FOO_PTR.all.X to T2, the
subtype of FOO_T1_PTR would be a lie, because the referenced object
would now have X = T2.
The only work-around I know of is to enclose the discriminated record in
another record, such as:
type HOLDER_T is record
R : RECORD_T;
end record;
type PTR_T is access HOLDER_T;
--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Unexpected discriminant check failure involving access types
2015-08-10 14:33 ` Niklas Holsti
@ 2015-08-10 14:56 ` Markus Schöpflin
2015-08-10 19:43 ` Niklas Holsti
0 siblings, 1 reply; 7+ messages in thread
From: Markus Schöpflin @ 2015-08-10 14:56 UTC (permalink / raw)
Am 10.08.2015 um 16:33 schrieb Niklas Holsti:
> On 15-08-10 15:38 , Markus Schöpflin wrote:
>> Given the following piece of code:
>>
>> ---%<---
>> 1 procedure TEST
>> 2 is
>> 3 type T is (T1, T2);
>> 4
>> 5 type RECORD_T (X : T := T1) is record
>> 6 null;
>> 7 end record;
>> 8
>> 9 type PTR_T is access RECORD_T;
>> 10
>> 11 FOO : RECORD_T;
>> 12 FOO_PTR : constant PTR_T := new RECORD_T;
>> 13
>> 14 FOO1 : constant RECORD_T := (X => T1);
>> 15 FOO2 : constant RECORD_T := (X => T2);
>> 16 begin
>> 17 FOO := FOO1;
>> 18 FOO := FOO2;
>> 19
>> 20 FOO_PTR.all := FOO1;
>> 21 FOO_PTR.all := FOO2;
>> 22 end;
>> --->%---
>>
>> When compiled and executed, I get:
>>
>> > ./test
>>
>> raised CONSTRAINT_ERROR : test.adb:21 discriminant check failed
>>
>> Can anyone please explain me why I get a discriminant check error when
>> using access types? I would have expected it to work the same as for the
>> non-access case.
>
> This is a consequence of RM 4.8(6/3): "... If the designated type is
> composite, then the subtype of the created object is the designated subtype
> when the designated subtype is constrained or there is an ancestor of the
> designated type that has a constrained partial view; otherwise, the created
> object is constrained by its initial value (even if the designated subtype is
> unconstrained with defaults)."
>
> In other words, the object FOO_PTR.all is constrained and it is not possible
> to change its discriminants -- the default value given to the discriminant X,
> which means that FOO is unconstrained, does not have the same effect on an
> allocated object.
OK, understood.
> The AARM motivates this rule as follows: "All objects created by an allocator
> are aliased, and most aliased composite objects need to be constrained so that
> access subtypes work reasonably." In other words, there could be a
> declarations like
>
> type PTR_T1_T is access all RECORD_T (X => T1);
> FOO_T1_PTR : PTR_T1_T;
>
> and statements
>
> FOO_T1_PTR := PTR_T1_T (FOO_PTR);
>
> Now FOO_PTR and FOO_T1_PTR point to the same object (the allocated one), with
> X = T1. If the program could now change FOO_PTR.all.X to T2, the subtype of
> FOO_T1_PTR would be a lie, because the referenced object would now have X = T2.
Makes sense. But right now I'm surprised that
FOO_T1_PTR := PTR_T1_T (FOO_PTR);
is actually allowed. Consider:
FOO : aliased RECORD_T;
FOO_T1_PTR : PTR_T1_T := PTR_T1_T'(FOO'Access);
There you get the (expected) error that the "object subtype must statically
match the designated subtype".
> The only work-around I know of is to enclose the discriminated record in
> another record, such as:
>
> type HOLDER_T is record
> R : RECORD_T;
> end record;
>
> type PTR_T is access HOLDER_T;
Thankfully, in my case the solution was even more simple, as we were able to
eliminate the access type altogether.
Thanks for your detailed explanation,
Markus
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Unexpected discriminant check failure involving access types
2015-08-10 14:20 ` Markus Schöpflin
@ 2015-08-10 19:00 ` Randy Brukardt
0 siblings, 0 replies; 7+ messages in thread
From: Randy Brukardt @ 2015-08-10 19:00 UTC (permalink / raw)
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1576 bytes --]
"Markus Schöpflin" <no.spam@spam.spam> wrote in message
news:55C8B334.2010102@spam.spam...
...
> I still don't get it: I would have expected the objects FOO and
> FOO_PTR.all to be identical in behaviour.
You would have been wrong.
>Why is "new RECORD_T" creating a
> constrained record and just using "RECORD_T" not?
Because that's what Ada 83 specified and it is incompatible to change it.
It's known to be stupid, but even a talented a designer as Jean Ichbiah was
will make some mistakes.
I'm not certain as to why Ada 83 adopted that model, probably you'd have to
look in the Rationale.
Anyway, every Ada programmer knows (or soon will find out) that one has to
make mutable discriminated records components (never a top-level object)
when allocated. There are a lot of records like:
type Record_Wrapper_T is record
C : Record_T;
end record;
(Note that this is why the restriction is stupid, one can easily cause
whatever complications were supposedly being eliminated by using a
component.)
Anyway, the rule in question is 4.8(6/3), and the technical term is
"constrained by its initial value". It's the same mechanism that is used if
Record_T had been indefinite (had no default discriminant value).
Note that we created a "hole" in this rule for completions of (constrainted)
private types, else there was a practical privacy breakage (some assignments
might fail for no good reason from the clients perspective). That was
controversal, and its unlikely we'd ever go further.
Randy.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Unexpected discriminant check failure involving access types
2015-08-10 14:56 ` Markus Schöpflin
@ 2015-08-10 19:43 ` Niklas Holsti
0 siblings, 0 replies; 7+ messages in thread
From: Niklas Holsti @ 2015-08-10 19:43 UTC (permalink / raw)
On 15-08-10 17:56 , Markus Schöpflin wrote:
> Am 10.08.2015 um 16:33 schrieb Niklas Holsti:
>> On 15-08-10 15:38 , Markus Schöpflin wrote:
>>> Given the following piece of code:
>>>
>>> ---%<---
>>> 1 procedure TEST
>>> 2 is
>>> 3 type T is (T1, T2);
>>> 4
>>> 5 type RECORD_T (X : T := T1) is record
>>> 6 null;
>>> 7 end record;
>>> 8
>>> 9 type PTR_T is access RECORD_T;
>>> 10
>>> 11 FOO : RECORD_T;
>>> 12 FOO_PTR : constant PTR_T := new RECORD_T;
>>> 13
>>> 14 FOO1 : constant RECORD_T := (X => T1);
>>> 15 FOO2 : constant RECORD_T := (X => T2);
>>> 16 begin
>>> 17 FOO := FOO1;
>>> 18 FOO := FOO2;
>>> 19
>>> 20 FOO_PTR.all := FOO1;
>>> 21 FOO_PTR.all := FOO2;
>>> 22 end;
>>> --->%---
>>>
>>> When compiled and executed, I get:
>>>
>>> > ./test
>>>
>>> raised CONSTRAINT_ERROR : test.adb:21 discriminant check failed
>>>
>>> Can anyone please explain me why I get a discriminant check error when
>>> using access types? I would have expected it to work the same as for the
>>> non-access case.
>>
>> This is a consequence of RM 4.8(6/3): "... If the designated type
>> is composite, then the subtype of the created object is the
>> designated subtype when the designated subtype is constrained or
>> there is an ancestor of the designated type that has a constrained
>> partial view; otherwise, the created object is constrained by its
>> initial value (even if the designated subtype is unconstrained with
>> defaults)."
>>
>> In other words, the object FOO_PTR.all is constrained and it is
>> not possible to change its discriminants -- the default value given
>> to the discriminant X, which means that FOO is unconstrained, does
>> not have the same effect on an allocated object.
>
> OK, understood.
>
>> The AARM motivates this rule as follows: "All objects created by
>> an allocator are aliased, and most aliased composite objects need
>> to be constrained so that access subtypes work reasonably." In
>> other words, there could be a declarations like
>>
>> type PTR_T1_T is access all RECORD_T (X => T1);
>> FOO_T1_PTR : PTR_T1_T;
>>
>> and statements
>>
>> FOO_T1_PTR := PTR_T1_T (FOO_PTR);
>>
>> Now FOO_PTR and FOO_T1_PTR point to the same object (the allocated
>> one), with X = T1. If the program could now change FOO_PTR.all.X to
>> T2, the subtype of FOO_T1_PTR would be a lie, because the
>> referenced object would now have X = T2.
>
> Makes sense. But right now I'm surprised that
>
> FOO_T1_PTR := PTR_T1_T (FOO_PTR);
>
> is actually allowed.
The access-type conversion involves a run-time check that FOO_PTR.all
satisfies the constraints for the designated type of PTR_T1_T, that is,
that FOO_PTR.all.X = T1. I think this is specified in RM 4.6(50): "...
any checks associated with evaluating a conversion to the target
designated subtype are performed." Constraint_Error results if the check
fails.
> Consider:
>
> FOO : aliased RECORD_T;
> FOO_T1_PTR : PTR_T1_T := PTR_T1_T'(FOO'Access);
>
> There you get the (expected) error that the "object subtype must
> statically match the designated subtype".
That's a qualified expression, not a type conversion. I suppose that
explains the difference.
--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-08-10 19:43 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-10 12:38 Unexpected discriminant check failure involving access types Markus Schöpflin
2015-08-10 13:14 ` Mark Lorenzen
2015-08-10 14:20 ` Markus Schöpflin
2015-08-10 19:00 ` Randy Brukardt
2015-08-10 14:33 ` Niklas Holsti
2015-08-10 14:56 ` Markus Schöpflin
2015-08-10 19:43 ` Niklas Holsti
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox