Proposed update to Analysis and Elaboration of subprograms and protected types
Proposal background
This is from @cfgardiner based on a discussion I had with him. Recording it here. I don't know if there is anything that can and/or should be done to address this as it once you get into it gets real complicated.
Is your capability/feature request related to a problem?
During the analysis of packages, both a subprogram declaration and body are analyzed, a protected type declaration and its body are analyzed, and a deferred constant declaration and the corresponding full constant declaration are analyzed. At this point, it is established that
- for every subprogram declaration there is a corresponding body,
- for every protected type declaration, there is a corresponding, and
During elaboration of a package declaration, the subprogram declaration is elaborated, and the protected type declaration is elaborated.
However, neither of these can be used in other declarations in the package declaration
since the corresponding subprogram body or protected type body
has not been elaborated yet.
For example, the following code is illegal:
package P is
function F (I : integer) return integer ;
signal S : integer := F(2) ;
end package P ;
package body P is
function F (I : integer) return integer is
begin
return I + 1 ;
end function F ;
end package body P ;
This also prevents declaration of a shared variable of a protected type in the same package that declares the protected type itself - since the protected type body must be in the package body.
@cfgardiner please add your protected type example here
The internals of subprograms and protected types are not elaborated until they are used. Instead, elaboration of the subprogram body and protected type body in the declaration simply establish its existence:
From 14.4.2.2 Subprogram declarations, bodies, and instantiations
Elaboration of a subprogram body, other than the subprogram body of an uninstantiated subprogram, has no effect other than to establish that the body can, from then on, be used for the execution of calls of the subprogram. Elaboration of a subprogram body of an uninstantiated subprogram has no effect.
From 14.4.2.3 Type declarations and instantiations
Elaboration of a protected type body has no effect other than to establish that the body, from then on, can be used during the elaboration of objects of the given protected type.
Describe the solution you'd like
Elaboration of subprogram bodies and protected type bodies only establishes the existence of the subprogram body or protected type body. However, from analysis, we already know these exist, and we should already know about where these are. If analysis were to save such artifacts that could then they could be used during elaboration of the declaration to establish the existence of the subprogram body and protected type body. And hence, the subprogram body and protected type body could be elaborated at the same time as the corresponding subprogram declaration and protected type declaration.
Evidence of this is already apparent in current simulator implementations as some implementations support this capability without any messaging and others produce errors of the form "Error (Suppressible)".
Issues with the solution
The goal of course is to allow a declaration that uses said subprogram or protected type in the package declaration as shown above. However, what happens if while elaborating the declaration that either calls the subprogram or is of the protected type, a definition that references a package local declaration, such as a constant, subprogram, or protected type, is attempted to be elaborated.
package P is
function F (I : integer) return integer ;
signal S : integer := F(2) ;
end package P ;
package body P is
function LocalF (I : integer) return integer is
begin
return I + 1 ;
end function LocalF ;
function F (I : integer) return integer is
begin
return LocalF(I) ;
end function F ;
end package body P ;
In this case, elaboration will fail due to the item not having been declared yet.
However, it is felt that this case is in the minority of the use cases, and in addition, it can be worked around by simply making the definition public (ie: have a corresponding declaration in the package header). Hence, a user has a path to a methodology that will indeed always work.
Describe alternatives you've considered
There is a simple work around here. Define the shared variable and/or function in a separate package from the one that uses it.
Related issues include
Lets be honest, even with the notation that is proposed in the Deferred Shared Variables in we are still going to have to address the same issues in elaboration - or we just kick the can down the road a little further - you can create the object, but you cannot use it until it is fully elaborated - which means you cannot use it in a declaration - as it turns out, that is potentially a significant limitation that would damage use models more than simply defining the shared variable in a separate package from its definition.
Potentially related items that are not taken on by this proposal
It might be possible to handle deferred constants in a similar manner, however, I left them out as the elaboration of the full constant declaration that corresponds to a deferred constant declaration may be more complicated since it may call a subprogram (function) that is local to the package body.
During the analysis of a package, a deferred constant declaration and the corresponding full constant declaration are analyzed. At this point, it is established that
- for every deferred constant declaration, there is a corresponding full constant declaration
During elaboration of a package declaration, the deferred constant declaration is elaborated.
However, this cannot be used in other declarations in the package declaration
full constant declaration has not been elaborated yet.