On Jun 16, 2007, at 11:52 AM, Mark Mitchell wrote:
Daniel Jacobowitz wrote:
This doesn't make a lick of sense to me. If the type is hidden, how
on earth can it get a member function _of that type_ from another
library? That library would, by definition, have to have a type of
the same name... but it would be a "different" type.
You and Chris are taking the view that "the type" has a location.
But,
a lot of people don't look at it this way. The things that have
locations are variables (including class data) and functions. After
all, types don't appear in object files; only variables and
functions do.
That is a limited view of things based on the current implementation
of GCC. When future developments (e.g. LTO) occur, this will change:
types certainly do live in object files.
Even now, "types" can live in object files through debug info, RTTI,
vtables, etc. Obviously there is a subset of cases where these don't
apply and where the approach you propose can make sense.
Furthermore, you're taking the view that:
__attribute__((visibility ("hidden"))
on a type means something about visibility of the type in a linguistic
sense, i.e., that it provides some kind of scoping, perhaps like an
anonymous namespace that is different in each shared library.
Yes.
But, the visibility attribute is only specified in terms of its
effects
on ELF symbols, not as having C++ semantics per se. The hidden
visibility attribute says that all members of the class have hidden
visibility, unless otherwise specified.
I'll paraphrase this as saying: "this is already an extension, not a
standard - we can extend the extension without remorse".
We also allow:
struct __attribute__((visibility("hidden"))) S {
__attribute__((visibility("default"))) void f();
void g();
};
which may seem equally odd: it says that you can call a function from
outside this translation unit even though you can't see the type.
But,
code like this is reasonable; it says that within the defining shared
object you can call all the functions, but that elsewhere you can call
"f" but not "g". (That's orthogonal to C++ access specifiers; private
functions can have default visibility, and public ones can have hidden
visibility.)
The above class should be exactly the same as:
struct S {
__attribute__((visibility("default"))) void f();
__attribute__((visibility("hidden"))) void g();
};
since there is no virtual table or other class data.
Because there is no standard to reference, I think it's important to
consider these things in terms of explainability. It is very easy
(and common) to explain visibility and anon namespaces in terms of
types (when applied to a type).
I notice that your original patch did not include a documentation
patch explaining the new semantics of the extension. I believe it
would be very difficult to convey the proposed semantics to people
who are not familiar with the Itanium ABI class layout and other
related details of the G++ implementation. I suspect that the
realview compiler accepts this as an oversight or a bug, not as an
intentional feature.
For better or worse (usually worse), people's understanding of the
language they code in is often defined by what their compiler happens
to accept. Because this is an (one of many) il-documented extension,
the *only* documentation is in what the compiler accepts.
How does that serve our users?
There are two conflicting goals to balance:
1. Define our extensions as well as possible and make their semantics
as explainable and logical as possible.
2. Compile existing code with maximum compatibility.
To me, the best way to handle this is to reject this by default
(based on #1). To handle #2, add a flag (defaulting to off) to
enable this extended extension. In the diagnostic, tell the user
about the option, and in the manual document the option and the issue.
I believe that rejecting this by default is important because people
often define what is valid by what their compiler accepts, not what
the standard says or what is logically consistent. :)
-Chris