010301.2 A T. Allen Ada Nested inlines

PURPOSE:

Issue #1:

I believe that the wording of 3.3.8.2 does not allow for nested inlines
because of these restrictions:

    1) An abstract instance tree consists of its root and all children of that
       root (transitively).
    2) A concrete instance tree consists of its root and all children of that
       root (transitively).
    3) Each concrete instance tree is uniquely associated with exactly one
       abstract instance tree.
    4) Each entry within a concrete instance tree is associated with one
       particular entry in the associated abstract instance tree.

Any inline subroutine nested within outer inline subroutine and called from
that outer inline subroutine would break this relationship because:

    1) the declaration of the nested inline subroutine would be considered
       part of its own abstract instance tree and also part of the outer
       inline subroutine's abstract instance tree.
    2) the inline expansion(s) of the nested inline subroutine would be
       considered part of their own concrete instance tree(s) and also part of
       the outer inline subroutine's concrete instance tree.

This problem cannot be solved by insisting that the abstract instance tree
for the outer inline subroutine contain appropriate abstract instance entries
for each nested inline expansion, either. This is because, from concrete
instance to concrete instance of the outer inline subroutine, the nested
inline subroutine might be expanded inline or called out-of-line, as the
compiler chose (or even as the user chosen, via optimization options).

I propose that the definition of an abstract instance tree be changed
slightly to exclude any abstract instance trees nested within it. Likewise,
the definition of a concrete instance tree should be changed to exclude any
concrete instance trees nested within it. I suspect this was the intent from
the start, so you may just want to think of this as a clarification.

(Also see Issue #5 below, which elaborates on this more.)

Issue #2:

The set of attributes listed in 3.3.8.1 to be excluded from an abstract
instance tree, and the same set in parentheses in 3.3.8.2 are too C-centric.
They don't take into account additional concrete-instance-dependent
attributes that might be added by new languages and/or vendors. I propose
making the text more vague and changing the sets into suggested lists for
C-like languages. Arguably, this is just a clarification, too.

Issue #3:

The rules that there be a one-to-one correspondence between entries in
concrete and abstract instance trees are unnecessarily restrictive, and the
exceptions presented _also_ are unnecessarily restrictive.

Basically, the exceptions presented are too C-centric. For example, in Ada,
it may be _necessary_ to describe an anonymous type in a concrete instance
tree because some aspect of its description depends on aspects of each
distinct concrete instance. Actually, come to think of it, I expect this
applies to C99's dynamically bounded arrays, too!

There are other cases, too. For instance, an anonymous type in a concrete
instance might contain no attributes (other than DW_AT_abstract_origin), but
still be necessary as a parent for some other debugging information entry
that does contain concrete-instance-dependent attributes.

In Ada, there will be other cases than those mentioned where a debugging
information entry in a concrete instance tree would contain no attributes
(other than DW_AT_abstract_origin). I see no point in describing such
entities.

So, I propose eliminating the exceptions as stated, and replacing them with
the permission (but not even the requirement) to omit any debugging
information entry from a concrete instance tree if it would contain no
attributes (other than DW_AT_abstract_origin) and no children. That should
be sufficiently vague as to be useful for any language, and should cover the
explicit exceptions from the DWARF 2.0.0 document, at least for C-like
languages. We could retain the explicit exceptions listed there as
suggestions for things to be omitted in C-like languages.

Issue #3b:

Furthermore, I would like to loosen the restriction on one-to-one
correspondence between concrete and abstract instance trees to allow a
concrete instance tree to omit a debugging information entry if that
debugging information entry becomes useless in the concrete instance.

For example, an anonymous variable object might be created in the abstract
instance tree to describe the upper bound of an array. In a particular
concrete instance, it might happen that the upper bound of the array is a
constant, and so it is described with a constant FORM on the array, instead
of the reference FORM that the abstract tree was expecting. There's really
no useful way to "finish" the description of that anonymous variable entry,
since it doesn't really exist in that inline expansion. Furthermore, no one
will really care about it, since it's anonymous and never referenced. So, I
propose that the concrete instance tree be allowed to omit that debugging
information entry, as well.

Issue #4:

It is useful for a concrete instance tree to create new debugging information
entries that were not contained in the abstract instance tree. This is true
in cases where there is no way to know, when generating the abstract instance
tree, that a given entity will be needed, say, as part of the description of
another entity that was in both the abstract and concrete instance trees.

This issue is a counterpart to Issue #3b. For instance, it allows an
abstract instance tree to omit an anonymous variable created to hold the
bound of an array if it expects the bound usually will be static. In any
inline expansion where that expectation wasn't met, the debugging information
entry for the anonymous variable could be created on-the-fly.

Issue #5:

I think the DWARF 2.0.0 document is unclear on how to describe inline
subroutines that contain nested subroutines. To clarify, I am not talking
about concrete instances nested within other concrete instances, but rather
about inline subroutines that contain other subroutines, such that from the
nested subroutines ones could up-level reference variables from the outer
inline subroutine.

In the case where the nested subroutine isn't inline, then arguably it's
straightforward how to describe them. Still, I propose to add text to
clarify the issue and also to act as contrast the following text.

In the case where the nested subroutine is inline, it isn't clear whether or
not the abstract instance tree for the nested subroutine should be reiterated
in the concrete instance tree for the outer subroutine. We believe it will
include no new useful information, so applying the conclusion from Issue #3,
we think there is no point in reiterating it there.

Likewise, it isn't clear whether or not the abstract instance tree must
contain abstract concrete instance trees for any inline expansions that occur
for nested subroutines. We think there is no useful information that would
be emitted there, either, so think they should be omitted. (In such a case,
all the useful information would be in the concrete instance tree for the
nested subroutine within the concrete instance tree for the outer subroutine.)
This is an application of the proposal for Issue #1.

If the nested subroutine's abstract instance was reiterated in the outer
subroutine's concrete instances, or the nested subroutine's concrete
instances were required to be present in the outer subroutine's abstract
instance, this could create nasty chains of DW_AT_abstract_origin attributes.
And if both existed, it would be unclear which of them should be referenced
by the DW_AT_abstract_origin attribute in the nested subroutine's concrete
instances in the outer subroutine's concrete instances. Thinking about that
makes my brain hurt. This is yet another reason for disallowing any
debugging information entry from being in more than one abstract or concrete
instance tree (see Issue #1).

WORDING CHANGES:

3.3.8.1

        :

    Any subroutine that contains a DW_AT_inline attribute will be known as an
    "abstract instance root". Any set of abstract instance entries that are
    all children (either directly or indirectly) of some abstract instance
    root, together with the root itself, will be known as an "abstract
  | instance tree". However, in the case where an abstract instance tree is
  | nested within another abstract instance tree, the entries in the nested
  | abstract instance tree are not considered to be entries in the outer
  | abstract instance tree.

    A debugging information entry that is a member of an abstract instance
  | tree should not contain any attributes which describe aspects of the
  | subroutine which would vary between distinct inline expansions or distinct
  | out-of-line expansions. For example, the DW_AT_low_pc, DW_AT_high_pc,
  | DW_AT_ranges, DW_AT_entry_pc, DW_AT_location, DW_AT_return_addr,
  | DW_AT_start_scope, and DW_AT_segment attributes probably will need to be
  | omitted, but that list is not exhaustive.

        :

3.3.8.2

        :

    For the remainder of this discussion, any debugging information entry that
    is owned (either directly or indirectly) by a debugging information entry
    with the tag DW_TAG_inlined_subroutine will be referred to as a concrete
  | inlined instance entry. However, in the case where a concrete instance
  | tree is nested within another concrete instance tree, the entries in the
  | nested concrete instance tree are not considered to be entries in the
  | outer concrete instance tree.

        :

  | Concrete inlined instance entries may omit most of the attributes (except
  | for any that were omitted from the abstract instance entries because they
  | would vary between concrete inlined instances), that such entries would
  | otherwise normally have. In place of these omitted attributes, the
    concrete inlined instance entry has a DW_AT_abstract_origin attribute that
    may be used to obtain the missing information (indirectly) from the
    associated abstract instance entry. The value of the abstract origin
    attribute is a reference to the associated abstract instance entry.

        :

    For each pair of entries that are associated via a DW_AT_abstract_origin
    attribute, both members of the pair will have the same tag. So, for
    example, an entry with the tag DW_TAG_variable can only be associated with
    another entry that also has the tag DW_TAG_variable. The only exception
    to this rule is that the root of a concrete instance tree (which must
    always have the tag DW_TAG_inlined_subroutine) can only be associated with
    the root of its associated abstract instance tree (which must have the tag
    DW_TAG_subprogram).

  | The structure and content of any given concrete instance tree will be
  | generally analogous to the structure and content of its associated
  | abstract instance tree. There are a few exceptions:
  |
  |   1. Entries in the concrete instance tree which would contain only
  |      DW_AT_abstract_origin attributes and which would have no children
  |      may be omitted, because they would provide no useful information.
  |      In C-like languages, such entries frequently include those for
  |      anonymous types, and members of structure, union, or class types.
  |      If any entry within a concrete inlined instance tree needs to refer
  |      to an entity declared within the scope of the relevant inline
  |      subroutine and for which no concrete instance entry exists, the
  |      reference should simply refer to the abstract instance entry.
  |
  |   2. Entries in the concrete instance tree which are associated with
  |      entries in the abstract instance tree such that neither has a
  |      DW_AT_name attribute, and neither is referenced by any other
  |      debugging information entry may be omitted. This may happen for
  |      debugging information entries in the abstract instance trees that
  |      became unnecessary in the concrete instance tree because of
  |      additional information available there. For example, an anonymous
  |      variable might have been created and described in the abstract
  |      instance tree, but because of the actual parameters for a particular
  |      inline expansion, it could be described as a constant value without
  |      the need for that separate debugging information entry.
  |
  |   3. A concrete instance tree may contain entries which do not correspond
  |      to entries in the abstract instance tree to describe new entities
  |      that are specific to a particular inline expansion. In that case,
  |      they will not have associated entries in the abstract instance tree,
  |      should not contain DW_AT_abstract_origin attributes, and must
  |      contain all their own attributes directly. This allows an abstract
  |      instance tree to omit debugging information entries for anonymous
  |      entities if the implementation believes they are unlikely to be
  |      needed in most inline expansions. In any expansion which deviates
  |      from that expectation, the entries can be described in its concrete
  |      instance tree.

    If an entry within a concrete inlined instance tree contains attributes
    describing the declaration coordinates of that entry, then those
    attributes should refer to the file, line and column of the original
    declaration of the subroutine, not to the point at which it was inlined.

        :

  | 3.3.8.4 Nested Inline Subroutines
  |
  | Some languages and compilers may permit the logical nesting of a
  | subroutine within another subroutine, and may permit either the outer or
  | the nested subroutine, or both to be inline.
  |
  | For a non-inline subroutine nested within an inline subroutine, the nested
  | subroutine is described normally in both the abstract and concrete inlined
  | instance trees for the outer subroutine. All rules pertaining to the
  | abstract and concrete instance trees for the outer subroutine apply also
  | to the abstract and concrete instance entries for the nested subroutine.
  |
  | For an inline subroutine nested within another inlined subroutine, the
  | following rules apply to their abstract and concrete instance trees:
  |
  |   1. The abstract instance tree for the nested subroutine is described
  |      within the abstract instance tree for the outer subroutine according
  |      to the rules in section 3.3.8.1, and without regard to the fact that
  |      it is within an outer abstract instance tree.
  |   2. No abstract instance tree for a nested subroutine is described
  |      within the concrete instance tree for an outer subroutine.
  |   3. No concrete instance tree for a nested subroutine is described
  |      within the abstract instance tree for an outer subroutine.
  |   4. The concrete instance tree for any inline or out-of-line expansion
  |      of the nested subroutine is described within a concrete instance
  |      tree for the outer subroutine according to the rules in 3.3.8.2 or
  |      3.3.8.3, and without regard to the fact that it is within an
  |      outer concrete instance tree.


Adopted with editorial changes:  clarify intent; clarify 3.3.8.2 items 1, 2, 3; add example.