Version 1.1 of ais/ai-00131.txt

Unformatted version of ais/ai-00131.txt version 1.1
Other versions for file ais/ai-00131.txt

!standard B.3 (69)          98-05-05 AI95-00131/05
!class confirmation 96-11-19
!status work item (revised by Ted Baker, per action from St. Louis meeting) 96-05-05
!status work item (letter ballot was 10-3-0) 96-10-03
!status ARG approved 8-0-0 (subject to letter ballot) 96-06-17
!status work item 96-04-17
!status received 96-04-17
!priority High
!difficulty Hard
!subject Interface to C -- passing records as parameters of mode 'in'
!summary 96-11-19
The Implementation Advice in B.3(69) is correct as written.
!question 96-04-17
B.3(69) says:
Implementation Advice ... 69 An Ada parameter of a record type T, of any mode, is passed as a
t* argument to a C function, where t is the C struct corresponding to the Ada type T.
The problem with this is that if one has a C function that is passed a struct, then how can one pass an Ada record to that? One might think that if the Ada record is passed as an 'in' parameter, it will work. However, the above Implementation Advice implies that such an 'in' parameter will correspond to a t* on the C side, rather than a t.
!response 98-04-01
It was a mistake to require pass-by-reference for records passed to C functions. However, at this point, it would be disruptive to change the rule, and there is an alternative (see below).
The most important use of this interface is to take an existing C interface, and use it from Ada code (as opposed to taking an existing Ada interface, and mapping it to some corresponding C code).
Structs are passed by copy in C. This can be implemented by passing a copy of the struct (on the stack, in a register, or whatever), or by making a copy at the call site, and passing the address of that copy. Either way, whatever the C compiler does, the goal should be for the Ada compiler to mimic the C compiler's method of passing structs (not pointers to structs).
Nonetheless, we choose to keep the rule as is. Instead, implementations can solve the problem by supporting the following implementation-defined convention.
pragma Convention(C_Pass_By_Copy, Some_Record_Type);
The effect is that argument is passed by copy, i.e. in a manner consistent with what C expects if the corresponding formal in the C prototype is a struct (rather than a pointer to a struct).
Note that there is no issue for modes 'in out' and 'out'; C doesn't have these modes, and the closest correspondence to C is a pointer-to-struct argument.
The above convention is the minimum recommended level of support for portable applications interfacing to C. Some Implementations also provide other mechanisms. For example, GNAT also provides a pragma C_Pass_By_Copy that has a similar effect to the convention above, and has extended Import and Export pragmas that allow specification of passing mechanisms on a parameter by parameter basis. This AI does not discourage such other mechanisms, but recommends that at least the convention C_Pass_By_Copy be supported by all implementations.
!appendix

!section B.3(69)
!subject Interface to C -- passing records as parameters
!reference RM95-B.3(69)
!from Bob Duff
!reference 96-5483.a Robert A Duff 96-4-13>>
!discussion

This issue was pointed out by Robert Dewar.  Robert, please reply if my
message doesn't capture your understanding of the issue.

B.3(69) says:

                            Implementation Advice
   ...
   69  An Ada parameter of a record type T, of any mode, is passed as a
       t* argument to a C function, where t is the C struct
       corresponding to the Ada type T.

The problem with this is that if one has a C function that is passed a
struct, then how can one pass an Ada record to that?  One might think
that if the Ada record is passed as an 'in' parameter, it will work.
However, the above Implementation Advice implies that such an 'in'
parameter will correspond to a t* on the C side, rather than a t.

The above Advice makes sense for 'in out' and 'out' parameters, since C
doesn't have 'in out' and 'out', and t* is the closest match.  However,
for 'in' parameters, it seems that an Ada record should correspond to a
C struct, rather than a C pointer-to-struct.

Note that the most important use of this interface is to take an
existing C interface, and use it from Ada code (as opposed to taking an
existing Ada interface, and mapping it to some corresponding C code).

Structs are passed by copy in C.  This can be implemented by passing a
copy of the struct on the stack, or by making a copy at the call site,
and passing the address of that copy.  Either way, whatever the C
compiler does, the goal should be for the Ada compiler to mimic the C
compiler.

I suspect the idea behind B.3(69) was that most C programmers, most of
the time, do *not* pass structs, but instead pass pointers-to-structs.
However, this is not universal -- passing a bare struct makes sense, and
is done in some cases.

On the other hand, if the Ada type does not directly correspond to a C
struct, it might make sense to pass it as a "t*".  Examples: tagged
types, by-reference limited types, discriminated types whose size is not
known.

- Bob

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

!section B.3(69)
!subject Interface to C -- passing records as parameters
!reference RM95-B.3(69)
!from Robert Dewar
!reference 96-5485.a Robert Dewar 96-4-13>>
!discussion

Some notes on Bob's recent post

>Structs are passed by copy in C.  This can be implemented by passing a
>copy of the struct on the stack, or by making a copy at the call site,
                    ^^^^^^^^^^^^
                    or in registers

>and passing the address of that copy.  Either way, whatever the C
>compiler does, the goal should be for the Ada compiler to mimic the C
>compiler.

>I suspect the idea behind B.3(69) was that most C programmers, most of
>the time, do *not* pass structs, but instead pass pointers-to-structs.
>However, this is not universal -- passing a bare struct makes sense, and
>is done in some cases.

  This may have been the idea, but it is wrong, it is not at all unusual
  to pass struct's. An example we ran into recently occurs in the DCN
  threads interface, a widely implemented industry standard. A compiler
  following the referenced implementation advice could not interface to
  DCN threads.

  (GNAT does NOT follow this implementation advice!)


oops, it's DCE threads, not DCN!

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

Questions? Ask the ACAA Technical Agent