!standard 10.1.4 (07) 00-10-30 AI95-00245/01 !class confirmation 00-10-30 !status work item 00-10-30 !status received 00-10-30 !qualifier Clarification !priority Low !difficulty Medium !subject Consistency of inlined calls !summary The implementation must insure that a partition containing inlined subprograms is consistent. It can do this by requiring recompilation of units, or via a automatic recompilation mechanism. !question Consider a package P that contains explicitly inlined subprograms, and a main subprogram Q that is compiled after P's body and calls such subprograms. P's body is later changed and recompiled without any subsequent user actions causing Q to be recompiled or Q's code to be regenerated. May program Q be rejected at link time, or must the linker automatically regenerate Q's code to be consistent with the new version of P's body? (The program may be rejected.) Apparently, the obsolete version of P's body is not needed in the program because there is no semantic dependence on it, see 10.2(4). And the permission to remove Q from the environment when P's body is recompiled, see 10.1.4(7), is simply a permission. There are rules to prevent multiple versions of a compilation unit in a program, see 10.1.4(5), but they don't seem to help here because they are based on semantic dependence, and they are compile-time rules. !response The implementation permission to remove Q from the environment is intended to handle this case. It allows the implementation to require the recompilation of Q; alternatively, the implementation can automatically recompile Q at link-time. 10.2(27) ensures that an inconsistent partition cannot be linked. That means that an implementation that neither removed Q from the environment nor automatically recompiled it would be incorrect. !ACATS test An L-Test could be created to check that a program such as the one described is consistent. !appendix From: Dan Eilers Sent: Thursday, October 19, 2000 8:27 PM !topic consistency of inlined calls !reference RM95-10.1.4(5-7) !reference RM95-10.1.1(24-26) !reference RM95-10.2(4) !reference AARM95-10.1.4(7.d) !reference AARM95-10.1.4(10.a) !from Dan Eilers !discussion Consider a package P that contains explicitly inlined subprograms, and a main subprogram Q that is compiled after P's body and calls such subprograms. P's body is later changed and recompiled without any subsequent user actions causing Q to be recompiled or Q's code to be regenerated. May program Q be rejected at link time, or must the linker automatically regenerate Q's code to be consistent with the new version of P's body? Apparently, the obsolete version of P's body is not needed in the program because there is no semantic dependence on it, see 10.2(4). And the permission to remove Q from the environment when P's body is recompiled, see 10.1.4(7), is simply a permission. There are rules to prevent multiple versions of a compilation unit in a program, see 10.1.4(5), but they don't seem to help here because they are based on semantic dependence, and they are compile-time rules. The concept of automatic linktime regeneration of code is mentioned twice in the AARM, see 10.1.4(7.d) regarding inlined subprograms without an explicit pragma inline, and 10.1.4(10.a) regarding macro-expanded generics, but never even as implementation advise in the RM as far as I can tell. Note that the index for "dependence semantic" is missing 10.1.4(5) and 10.2(4), and the index for pragma inline is missing 10.1.4(7). **************************************************************** From: Tucker Taft Sent: Thursday, October 19, 2000 10:33 PM Program Q may be rejected at link time. Subprogram Q need not be implicitly recompiled, but rather it may be considered to be out-of-date. In contrast, instantiation bodies are required to be implicitly recompiled in Ada 95. > Apparently, the obsolete version of P's body is not needed in the program > because there is no semantic dependence on it, see 10.2(4). And the > permission to remove Q from the environment when P's body is recompiled, > see 10.1.4(7), is simply a permission. This is the key permission. This is intended to mean that the implementation may force the user to take an explicit action to get Q back into the environment (i.e. explicitly recompile it). In other words, Q may be considered "out of date." No such permission exists for generic instantiations if the generic body is updated, so the instantiations must remain in the environment, and the linker must not complain that they have become out-of-date. At least that was the intent. > ... There are rules to prevent multiple > versions of a compilation unit in a program, see 10.1.4(5), but they don't > seem to help here because they are based on semantic dependence, and they > are compile-time rules. > > The concept of automatic linktime regeneration of code is mentioned > twice in the AARM, see 10.1.4(7.d) regarding inlined subprograms without > an explicit pragma inline, and 10.1.4(10.a) regarding macro-expanded > generics, but never even as implementation advise in the RM as far as > I can tell. Automatic linktime regeneration is required for implicit inlining and macro-expanded generics, so no implementation advice is necessary. It is permitted, but not required for explicit inlining, and the manual gives no advice either way for this case. > Note that the index for "dependence semantic" is missing 10.1.4(5) and > 10.2(4), and the index for pragma inline is missing 10.1.4(7). **************************************************************** From: Dan Eilers Sent: Friday, October 20, 2000 1:24 AM Tuck wrote: > > And the > > permission to remove Q from the environment when P's body is recompiled, > > see 10.1.4(7), is simply a permission. > > This is the key permission. This is intended to mean > that the implementation may force the user to take > an explicit action to get Q back into the > environment (i.e. explicitly recompile it). In other > words, Q may be considered "out of date." I understood the environment to be a compile-time concept (see 10.1.4(1)), rather than a link-time concept. 10.1.4(5) requires a unit to exist in the environment in order to compile a unit that depends on it, but 10.2(27) has no corresponding requirement for linking. I assume that "consistency" in 10.2(27) is intended to have the same meaning as in 10.1.4(5), based on semantic dependency, which doesn't cover "out of date" inlines. Note: the index entry for "consistency among compilation units" should add 10.2(27). In an implementation where units are never removed from the environment as long as their source file still exists, could a program be rejected at link time for "out of date" inlines. **************************************************************** From: Tucker Taft Sent: Friday, October 20, 2000 10:52 AM Dan Eilers wrote: > I understood the environment to be a compile-time concept (see 10.1.4(1)), > rather than a link-time concept. The environment is a compile-time, link-time, and run-time concept (see 10.1.4(1), 10.2(13), and 10.2(25)). > 10.1.4(5) requires a unit to exist in the environment in order to > compile a unit that depends on it, but 10.2(27) has no corresponding > requirement for linking. > > I assume that "consistency" in 10.2(27) is intended to have the > same meaning as in 10.1.4(5), based on semantic dependency, > which doesn't cover "out of date" inlines. Out of date inlines is a concept that doesn't exist in the manual. Inlining is supposed to be semantically neutral, except for certain subtleties having to do with 11.6 "independence", so clearly an inlined call must be based on the same body as any out-of-line call. The "consistency" of 10.2(27) is intended to require that no two versions of the same unit will exist in the partition. The semantics of executing the partition are determined by the source code for the units included in the partition; whether or not the source is translated into some other form (e.g. machine code) is irrelevant to this, as is it irrelevant whether or not inline expansion is occurring (modulo 11.6). > Note: the index entry for "consistency among compilation units" > should add 10.2(27). Good point. > In an implementation where units are never removed from the environment > as long as their source file still exists, could a program be rejected > at link time for "out of date" inlines. From a legalistic point of view, the manual actually doesn't say anything about what are the full prerequisites to linking, since the whole process of building a partition is implementation defined. I think the intent was that the rules for compilation would apply to linking, in particular that if something is still "in" the environment with respect to compilation, it should be considered "in" the environment with respect to linking. However, now that I look through 10.2, I don't really see anything explicit to that effect, so I suppose your linker could be as "unfriendly" as you want it to be. From a practical point of view, the ACATS tests have generally made the interpretation suggested above, and presumably vendors have lived with it, and probably users have grown accustomed to the availability of a semi-automatic linking process. I think the key legalistic requirement is that *if* a unit gets included in an environment, then its semantics must be based on a single version of its source code and a single, consistent version of the source code of the other units. Whether the user has to take explicit actions before linking is not really specified by 10.2. By contrast, 10.1.4 seems clearer that no explicit actions are required before compiling in certain cases, such as a change to a generic body or an implicitly inlined body. **************************************************************** From: Robert Dewar Sent: Friday, October 20, 2000 11:02 AM <> Of course the answer is yes, it can be rejected, there is never a requirement for the linker to do "compilation" in this sense. **************************************************************** From: Dan Eilers Sent: Saturday, October 21, 2000 12:28 PM If there is never a requirement for the linker to do automatic "compilation" to fix up "out-of-date" explicit inlines, is there a requirement for the linker to do automatic "compilation" to fix up "out-of-date" units where the compiler acted "as if" there was an explicit inline on a unit that it noticed contained lots of very small subprograms? This seems to be required by AARM 10.1.4(7.d), but perhaps that should just be considered implementation advise and not be tested by ACATS. **************************************************************** From: Robert Dewar Sent: Saturday, October 21, 2000 7:14 PM <> Obviously if a compiler does something in "as-if" mode then it must do whatever is necessary to ensure that the behavior really is "as-if". **************************************************************** From: Dan Eilers Sent: Monday, October 23, 2000 3:38 AM I take that to mean no, there is no requirement for the linker to do automatic "compilation" for either explicit inlines or properly implemented implicit inlines, and so AARM 10.1.4(7.d) should not be tested by ACATS. Did I understand correctly? If so, I hope that AARM 10.1.4(10.a) should also not be tested for the same reason. **************************************************************** From: Randy Brukardt Sent: Monday, October 30, 2000 10:10 PM Dan said: > Note that the index for "dependence semantic" is missing 10.1.4(5) and > 10.2(4), and the index for pragma inline is missing 10.1.4(7). Based on my understanding of the RM's index, I don't think these would be justified. As I understand the index, it indexes only places where things are *defined*, not where they are *used*. These are all *uses*. (Whether that is a good idea is another issue altogether, but I think it is important to keep the index consistent.) **************************************************************** From: Randy Brukardt Sent: Monday, October 30, 2000 10:28 PM > I take that to mean no, there is no requirement for the linker to do > automatic "compilation" for either explicit inlines or properly > implemented implicit inlines, and so AARM 10.1.4(7.d) should not > be tested by ACATS. Did I understand correctly? If so, I hope > that AARM 10.1.4(10.a) should also not be tested for the same reason. I don't think Robert meant to imply that. I thought he meant that implicit inlines ought to behave "as-if" there is no inline at all. Certainly, *I* think that implicit inlines should be exactly that, and if that means that you have to do link-time compilation, so be it. (If you don't like that, don't implement implicit inlining!!!) OTOH, I don't think it would ever be possible for AARM 10.1.4(7.d) to be explicitly tested by an ACATS test: how could you possibly insure that a unit had an implicit inline? But certainly, your interpretation would allow an implementation to reject linking of any ACATS test that tried to replace a unit with a new body after compiling another unit containing a call to a subprogram in the first unit (because you could always claim that the subprogram had been implicitly inlined). That would be madness. So, whether or not 10.1.4(7.d) is tested, it is still true. And it has no bearing on whether 10.1.4(10.a) should be tested, given that there is a Defect Report (8652/0108) confirming 10.1.4(10-10.a). Indeed, there is already a test requiring this behavior. (I converted the test to a 'C' test after an implementor complained that the test was misclassified as an 'L' test.) **************************************************************** From: Robert Dewar Sent: Tuesday, October 31, 2000 7:18 AM <> Yes, of course that's what I meant, if you do anything like this implicitly, it needs to stay implicit :-) **************************************************************** From: Dan Eilers Sent: Wednesday, November 01, 2000 8:58 PM Randy wrote: > Certainly, *I* think that implicit inlines should be exactly that, and if > that means that you have to do link-time compilation, so be it. (If you > don't like that, don't implement implicit inlining!!!) Our implementation implements implicit inlines "as if" there was an explicit inline in the source code, taking advantage of the permission to remove units with out-of-date inlined code from the library. Are you saying our implementation violates the standard? > So, whether or not 10.1.4(7.d) is tested, it is still true. And it has no > bearing on whether 10.1.4(10.a) should be tested, given that there is a > Defect Report (8652/0108) confirming 10.1.4(10-10.a). Indeed, there is > already a test requiring this behavior. (I converted the test to a 'C' test > after an implementor complained that the test was misclassified as an 'L' > test.) I am familiar with Defect Report 8652/0108, and quite sure that it does not confirm or even mention AARM 10.1.4(10-10.a). 8652/0108 is a compile-time issue, (requiring the compiler not to reject a unit that depends on an incomplete generic unit). 10.1.4(10-10.a) is non-normative link-time advise regarding the commands for invoking the linker. Your C test for AARM 10.1.4(10-10.a) is invalid as a test for 8652/0108. A proper test for 8652/0108 would be a B test checking that no error was generated. **************************************************************** From: Dan Eilers Sent: Wednesday, November 01, 2000 8:33 PM Randy wrote: > As I understand the index, it indexes only places where things are > *defined*, not where they are *used*. This is a misunderstanding. **************************************************************** From: Robert Dewar Sent: Wednesday, November 01, 2000 10:05 PM <> Yes, I consider this non-compliant **************************************************************** From: Dan Eilers Sent: Thursday, November 02, 2000 2:52 AM Robert wrote: > < an explicit inline in the source code, taking advantage of the > permission to remove units with out-of-date inlined code from the > library. > > Are you saying our implementation violates the standard?>> > > Yes, I consider this non-compliant If true, surely this is an unintentional difference from Ada83 that should be fixed. **************************************************************** From: Robert Dewar Sent: Thursday, November 02, 2000 6:59 AM <> No, I think this would be a non-compliance in Ada 83 as well. If you allow arbitrary obsoleting of this kind, then an implementation can do all kinds of horrible things, and indeed you can easily create a situation where it is impossible to build some programs. **************************************************************** From: Randy Brukardt Sent: Thursday, November 02, 2000 2:07 PM > < that should be fixed.>> > > No, I think this would be a non-compliance in Ada 83 as well. > > If you allow arbitrary obsoleting of this kind, then an implementation > can do all kinds of horrible things, and indeed you can easily create > a situation where it is impossible to build some programs. Right. But keep in mind this only applies to the standard (ACATS compliant) mode. Certainly an implementation can have a mode that does something else useful for their customers (as per 1.1.5(11)). **************************************************************** From: Robert Dewar Sent: Thursday, November 02, 2000 8:04 PM A compiler can do anything it likes in non-standard mode, including for example compiling C++ instead of Ada :-) **************************************************************** From: Robert Dewar Sent: Thursday, November 02, 2000 10:12 AM To: ADA-COMMENT@ACM.ORG; ada-comment@ada-auth.org Subject: Re: [Ada-Comment] consistency of inlined calls <> Note that this is only a problem if it is visible, or more accurately if there is no way to make it transparent. For example, with GNAT, our "official" 100% RM-compliant compilation model looks like this: 1. Compilation is done by first using gnatchop (to deal with compilations and also with compiling configuration pragmas on their own), followed by compilations using gcc -c -gnatC, which diagnoses all illegalities and inserts the unit into the compilation environment (i.e. the ALI file). 2. Binding is done using gnatmake, which also happens to perform some code generation activity :-) Of course the RM has nothing to say about whether "code generation" (whatever that is, the term is not comprehensible in formal RM terms) takes place at "compile" time or "link" time. As long as implicit inlining and its necessary recompilations are hidden under the covers in a similar manner, then of course there is no issue of non-conformance with the compilation model in the RM. **************************************************************** From: Erhard Ploedereder Sent: Thursday, November 02, 2000 9:11 AM This issue (of dependents of generic units or of inline-caused dependencies) has been gone over for Ada87, by the 95 DRs and many others. In the end, the only consensus that was able to be achieved is one that no program shall reach execution with an inconsistent set of compilation units as the basis for the executed code. This is the AXIOM, basically stated in Note 10.1.4(8), to which the rules of the language are geared. And yes, implicit recompilation for implicit inlines and implicit recompilation of dependents of a generic, whose body has changed, are the most user-friendly behavior. The words in the manual indicate that intent. But, because of the many implementation-defined aspects of the compilation process, there are enough loopholes that other compile-time behavior can be equally argued to be "conforming", as long as the AXIOM is preserved. Explicitly mentioning all the possible compiler behaviors in 10.1.4(7) would really be counterproductive. In that sense DR108 is right in saying "10.1.4(7) is intended to be complete". The next sentence in DR108 acknowledges the leeway that implementations have anyway. In a way, 10.1.4(7) cannot be complete, ever, with so much implementation-dependence involved. What made this liberal implementation-definedness acceptable to the vast majority (including the then ACVC95-writers) is the fact that these issues have no way of endangering portability of Ada software, which is the main objective of having a rigorous language standard and conformance enforcement. **************************************************************** From: Dan Eilers Sent: Thursday, November 02, 2000 6:54 PM Randy wrote: > > < > that should be fixed.>> > > > > No, I think this would be a non-compliance in Ada 83 as well. > > > > If you allow arbitrary obsoleting of this kind, then an implementation > > can do all kinds of horrible things, and indeed you can easily create > > a situation where it is impossible to build some programs. > > Right. But keep in mind this only applies to the standard (ACATS compliant) > mode. Certainly an implementation can have a mode that does something else > useful for their customers (as per 1.1.5(11)). We do "as if" inlining in our standard mode. As Erhard notes, it is user friendly to have a way to do automatic recompilations. We of course have an "ada make" tool that will do such automatic recompilations, but we don't invoke this tool during validations, either as part of the compiler or as part of the linker. Nor do we believe it is reasonable or necessary to do so. **************************************************************** From: Randy Brukardt Sent: Thursday, November 02, 2000 8:17 PM Do you pass all of the ACATS tests that way? If so, no problem (even if it might be technically non-conforming). Otherwise, it is "necessary" ("reasonable" is just an opinion). (Of course, you could raise a dispute against particular tests -- I'll be happy to run those through the dispute process.) ****************************************************************