Version 1.1 of acs/ac-00164.txt

Unformatted version of acs/ac-00164.txt version 1.1
Other versions for file acs/ac-00164.txt

!standard 3.10.2(2/2)          08-06-15 AC95-00164/01
!standard 4.5.2(9.5/2)
!standard 4.5.2(9.6/2)
!class confirmation 08-06-15
!status received no action 08-06-15
!status received 08-06-05
!subject Can X'Access be used in universal_access equality?
!summary
!appendix

!topic Can X'Access be used in universal_access equality?
!reference 4.5.2, 3.10.2
!from Adam Beneschan 08-06-05
!discussion

The version of GNAT I'm using accepts this.  I think GNAT is wrong, but I wanted to bring this up in case the intent was to allow things like this but the current RM wording doesn't sanction it, or are ambiguous.

   package pak1 is
      type T3 is tagged null record;
      x1 : aliased T3;
      x2 : access T3;
      b1 : boolean := x2 = x1'Access;  -- legal?
   end pak1;

The question is, is the "=" operator legal?  I don't think it is, but GNAT doesn't give an error message.  Here's how I interpret the
wording:

4.5.2(9.5ff) says:

At least one of the operands of the equality operators for universal_access shall be of type universal_access, or both shall be of access-to-object types, or both shall be of access-to-subprogram types. Further:

    * When both are of access-to-object types, the designated types
      shall be the same or one shall cover the other, and if the
      designated types are elementary or array types, then the
      designated subtypes shall statically match;

    * When both are of access-to-subprogram types, the designated
      profiles shall be subtype conformant.

The problem is that before we apply this rule, we need to know what the type of X1'Access is.  And as far as I can tell, X1'Access does not have any type independently of context.  3.10.2(24):

    X'Access yields an access value that designates the object denoted
    by X. The type of X'Access is an access-to-object type, as
    determined by the expected type. The expected type shall be a
    general access type.  X shall denote an aliased view of an object,
    including possibly the current instance (see 8.6) of a limited
    type within its definition, or a formal parameter or generic
    formal object of a tagged type. The view denoted by the prefix X
    shall satisfy the following additional requirements, presuming the
    expected type for X'Access is the general access type A with
    designated type D: ...

Thus, before we know what the type of X1'Access is, we need to know what the expected type is.  But since there's nothing that would allow the expected type of X1'Access, when used as the *right* parameter to "=", to be the type of the left parameter, the 
only "expected type" we could possibly have is the type of the parameter to "=", which is universal_access.  And I don't think it's legal for the expected type of X1'Access to be universal_access; nothing I know of says that universal_access is a general a
ccess type or an access-to-object type, and the last clause of 3.10.2(24) presumes that the expected type has a designated type D, which universal_access certainly doesn't have.

So it seems to me that the "=" operator on universal_access cannot have X'Access as an operand.

Is my interpretation correct?

Is this what is intended, or was it intended that this use of "="
should be legal?

****************************************************************

From: Randy Brukardt
Date: Thursday, June 12, 2008  12:22 AM

...
>    package pak1 is
>       type T3 is tagged null record;
>       x1 : aliased T3;
>       x2 : access T3;
>       b1 : boolean := x2 = x1'Access;  -- legal?
>    end pak1;
>
> The question is, is the "=" operator legal?  I don't think it is, but
> GNAT doesn't give an error message.

IMHO, GNAT is wrong.

...
> The problem is that before we apply this rule [4.5.2(9.1/2)], we need
> to know what the type of X1'Access is.  And as far as I can tell,
> X1'Access does not have any type independently of context.

You forgot 3.10.2(2/2) again. It defines the name resolution rules for 'Access.
(Remember that attributes can have them if separately defined.)

It requires the attribute to have a "single access type". The rule for "=" on
universal_access identifies "universal_access" as the type, but clearly 'Access
cannot have this type (only null has it explicitly). [You also came to that
conclusion, noting that universal_access is not an access-to-object type.] It
can be implicitly converted to that type, but that is specifically disallowed by
8.6(27/2) [just because the type_conversion is implicit doesn't suddenly make it
legal].

Thus this is illegal and GNAT is wrong. QED.

****************************************************************

Summary of private conversation between Randy Brukardt and Edmond Schonberg,
June 12-14.

**Ed:
Not so sure. How do I check that two access parameters alias the same
object? Do I have to write A1.all'address?

**Randy:
'fraid I don't see the problem. You are describing something like:

    procedure Foo (A, B : access Something) is
    begin
        if A = B then -- OK.
            -- Do something.
        else -- Do something else.
        end if;
    end if;

No need for 'access here. A.all'Access is a long winded way to write A.

If you want to compare a fixed object with an access parameter, you'd
have to either use a qualification with a named type or a rename: but
that's important so that we know the exact type of the 'Access. That
would look like:

    procedure Foo (A : access Something) is
        type Local_Acc is access all Something;
    begin
        if A = Local_Acc'(Global'Access) then ...

or

    procedure Foo (A : access Something) is
        Acc_to_Global : access Something renames Global'Access;
    begin
        if A = Acc_to_Global then ...

The latter is probably better because it preserves accessibility (and doesn't
make any junk accessibility checks).

Remember that these rules are written so that
    if Local_Acc'(Global'Access) = null then ...
is not ambiguious. "null" and 'Access have similar resolution rules.

**Ed:
> No need for 'access here. A.all'Access is a long winded way to write
> A.

    procedure Foo (A1 : access T;  A2 : access T) is
    begin
           if A1 = A2 then   --  which equality?   these are two
different anonymous access types, and neither is universal.
What am I missing? Am I supposed to qualify them here?

**Randy:
There's no requirement that these operands be the same type: they're both
convertible into universal_access, one of the operands is a specific anonymous
access type, the designated types are the same, and we'll assume that there
isn't a user-defined equivalent somewhere (and even then you can prefix "=" with
Standard to get this one). So this is legal as written (that was the whole idea,
IMHO) -- all of the requirements are satisfied. What's the problem??

There is almost no sane reason to use 'Access here, and if you need to do so,
you can use a renames to effectively qualify it. I don't see any issue here.

**Ed:
I certainly agree, but then I have troubles understanding why Adam's original
example is problematic. I guess it's the way the rule to resolve 'Access is
phrased, but intuitively there is no problem at all.  My first attempt to
implement this properly in GNAT produced the talmudic message:

   illegal operands for "="
   left operand has type  access to T
   right operand has type access to T

  which is really illuminating :-)!

**Randy:
It's the same reason that
    Some_Acc(Obj'Access)
is illegal. The problem is that without identifying a specific type for
Obj'Access, you can't check the accessibility rules and other fun legality rules
of 3.10.2(24-30) -- the different possible types would get different answers for
the rules. (Imagine that you only have an access to variable type handy, and Obj
is a constant. Is Obj'Access legal or not??)

That probably could have been worked around for the equality case: but we'd need
a bunch of special rules ("ignore all of that stuff about legality if the
attribute is used as the operand of a universal "=" operator") and *that* seems
like a can of worms best left unopened (because it is unlikely that you could
really ignore *all* of the legality rules). And there is a simple (if not
obvious) workaround possible if it actually comes up (which it would only
rarely).

**Ed:
OK, understood now.  Not that I am happy with the fact that given
    procedure Mangle (Obj1, Obj2 : T);

I cannot write in the body of Mangle:
      if Obj1'access = Obj2'access then ...

but of course I could use 'address.

**Randy:
Not a good idea anyway unless you know that T is a by-reference type. Otherwise,
the result is implementation-defined or (worse) just False for a by-copy type.

If T is by-reference, just write:

     declare
         Acc_Obj1 : access T renames Obj1'access;
         Acc_Obj2 : access T renames Obj2'access;
     begin
         if Acc_Obj1 = Acc_Obj2 then ...

which is legal (and surely better than using 'Address).

****************************************************************

Questions? Ask the ACAA Technical Agent