Version 1.1 of ai05s/ai05-0113-1.txt
!standard 3.9(12.1/2) 08-10-06 AI05-0113-1/01
!standard 3.9(25.3/2)
!standard 13.3(76)
!class binding interpretation 08-10-06
!status work item 08-10-06
!status received 08-06-13
!priority Low
!difficulty Easy
!qualifier Omission
!subject Conflicting external tags
!summary
If a user-specified external tag S'External_Tag is the same as T'External_Tag for some
other type, execution of the partition is erroneous.
!question
If users specify values for 'External_Tags, it's possible that the external tags
for two different type declarations may be the same, probably by accident.
!recommendation
(See Summary.)
!wording
Add before 3.9(25.3/2):
Bounded (run-time) Errors
It is a bounded error if the value of External passed to Tags.External_Tag identifies
more than one tagged type with the appropriate ancestor and accessibility level.
Either Program_Error is raised, or one of the identified tagged types is returned.
AARM Note: This can happen in two cases:
* If a specified external tag matches that of some other type in the partition.
This is already erroneous (see 13.3).
* If a generic body contains a derivation of a tagged type declared outside of
the generic, and there are multiple instances at the same accessibility level.
(There is an exception to the general requirement that default external tags
be unique for this case.) This second case is the one that this rule is
intended to catch.
Add before 13.3(76):
Erroneous Execution
If a non-confirming user-specified external tag S'External_Tag is the same as
T'External_Tag for some other tagged type, execution of the partition is erroneous.
AARM Note
An implementation can raise an exception such as Program_Error if this can be detected.
Otherwise, it is likely that Tags.Internal_Tag and Tags.Descendant_Tag will return
an unspecified tag.
!discussion
We make the specification of the tag erroneous so that an implementation can
raise an exception should it be able to detect the problem.
Requiring a runtime check would require some sort of runtime table to check
External_Tag names; the table would need exclusion in case multiple tasks are
creating tagged types at the same time. That seems ike unnecessary overhead
for a very unlikely case.
A post-compilation check is not possible in general, as tagged types can
be created in subprograms and tasks, and it is possible that the two types
with conflicting external tags never exist at the same time. Such a program
is not erroneous. [Or do we want to go further and ban this, too?? Seems
like a slippery slope... - ED]
Note that for default external tags, the implementation needs to prevent
conflicts from happening (as noted in 13.3(76)). However, generic instance
bodies are excepted from this requirement, and thus we need to worry about
that case, as well. Internal_Tag is already covered, as it is defined to
return "a tag" (that was intended to cover recursion, but it works here,
too). So we just need a rule for Dependent_Tag. We made it a Bounded Error
to minimize disruption but still to allow detection.
--!corrigendum 13.3(76)
!ACATS Test
!appendix
!topic External tag clashes
!reference AI95-00260, 13.3(73-76), 3.9(12.1)
!from Adam Beneschan 08-06-13 !discussion
It's occurred to me that if users specify values for 'External_Tags, it's possible that
the external tags for two different type declarations may be the same, probably by accident.
(Note: I'm using the term "type declaration" here because I don't want to discuss the
case where distinct types are elaborated by the same type declaration, in a recursive
routine or a task type, e.g. I think the semantics in that case are probably fine.
My terminology may not be precisely correct here, but hopefully I'm making myself
understood.)
For distinct type declarations, the language requires that the
*default* external tags be distinct (outside of generic instances).
But AI-260 raises the possibility that a programmer may want to specify human-readable
external tags for reading/writing XML files using streams. And it is conceivable
that two different programmers working on different packages, or even the same
programmer on a bad day, may decide to use the same 'External_Tag for different
types. (Also possible, but probably less likely, a programmer may choose for an
external tag a value that the implementation has chosen as the default
'External_Tag for some other type.) This could lead to some obvious
problems---the tag in the XML file will be ambiguous, and very bad things could
happen when it's read back in by an Ada program.
One thing I noticed is that, while 3.9(12) has been changed from "Internal_Tag
returns the tag" to "Internal_Tag returns a tag", 3.9(12.1) is worded in a way
that assumes that there will be only one type corresponding to an external tag:
"The function Descendant_Tag returns *the* (internal) tag for *the* type..."
Since it's possible that more than one type may correspond to an external tag,
this paragraph should probably say something about the possibility ("If more
than one such type meets the requirements, the function result is the tag for
an arbitrary such type").
But what I really think is necessary, that I don't see in the RM, is something
like an Implementation Permission that if it is determined at runtime that two
distinct type declarations have the same external tag (other than in two
instances of the same generic, or maybe other cases where the tags are expected
to be the same), Program_Error may be raised as soon as the situation is
detected. I'm not convinced that there's anything in the RM that currently
allows this behavior.
****************************************************************
From: Thomas Quinot
Date: Monday, June 16, 2008 12:54 PM
I'd simply make that erroneous.
****************************************************************
From: Adam Beneschan
Date: Tuesday, June 17, 2008 10:23 AM
That might work; if it's decreed that a program that has the same
External_Tag for two distinct types (outside of instances) is erroneous,
then any behavior, including raising an exception during libary package
elaboration, is allowed. (So is erasing the hard disk, but I doubt that
would actually happen.)
I just wanted to mention that I don't think it's enough to say that programs
with duplicate External_Tags are erroneous if they use Ada.Tags.Internal_Tag
or Descendant_Tag. Clearly, if Internal_Tag or Descendant_Tag is called with
an external tag and two or more distinct types have that same tag, the
functions could return the wrong tag and serious havoc could result
(particularly if Descendant_Tag is called from T'Class'Input, or if the
resulting tag is used as a parameter to Generic_Dispatching_Constructor).
But even a program that doesn't use either of those routines could cause
problems. For example, a program that uses T'Class'Output (e.g. for
writing an XML file) that thinks the external tag for two different types
is the same, could end up writing a useless output file, which could later
cause havoc for another program (even a non-Ada program) that tries to
read it. That's why I think an error like this should be caught early.
But whether this is done by an Implementation Permission or by stating
that such programs are erroneous, I don't know. I'll leave it to others
to decide what the best way of dealing with this is, if they agree that
it needs to be dealt with.
****************************************************************
Questions? Ask the ACAA Technical Agent