This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Anonymous Namespaces


Chris Lattner <sabre@nondot.org> writes:

| On 31 Jan 2004, Gabriel Dos Reis wrote:
| > | Yes, we use the GCC "3.4" parser, so if it does, we do.  We also don't
| > | support export yet.  Regardless, if export was implemented, and an entity
| > | was not involved with an exported template, it should still be marked as
| > | internal.
| >
| > You can't have that information availabale at parsing time.  You'd
| > need to postpone the tramsutation to link time.  The reason is that,
| > the instantiation of exported template can trigger  instantiation in
| > chains and those usually implies name lookup  -- which will happen at
| > sort of "link time"  when the different translation units are being
| > combined together.  The second phase of name critically needs to know
| 
| Ok, that makes sense.  When export is an issue, this can certainly be
| corrected.  Link time is "soon enough" for LLVM's purposes anyway.

In fact, even without export implementation the issue is still there,
right now!  The following example is for the inclusion model (the one
g++ currently implements).  

    namespace n {
      template<class T, class U>
        void func(T t, U u)
        { gunc(t, u); }
    }

   namespace my {
      struct fu;

      namespace {
        struct mu { };

        void gunc(fu, mu);
      }

      struct fu { };       

      namespace {
        void gunc(fu, mu) { }
      } 
   }


   int main() {
     my::fu f;
     my::mu m;
     n::func(f, m); 
   } 

During the instantiation of n::func(T, U) with T = my::fu, U = my::mu,
argument-dependent name lookup will find gunc() in the unnamed
namespace in my:: because it has external linkage.  
However, if you change gunc() to a static function, then name
look up will not succeed.  You'll be incorrectly rejecting a
well-formed program.
So, no "export" needed to illustrate the problem.  You can start
reverting your transmutation :-/

Now, with export, the issue is more involved because the defintion of
n::func() could be exported, i.e. defined in a separate translation
unit.  But then in the translation unit that contains the invokation
to n::func(), there is evidence that my::gunc() is used.  Only the
instantiation unit will tell you.  So, in translation-unit-at-time
mode, in general, you don't have enough information to decide.  You
need to go to the instantiation unit. 

| > | It's not just the inliner, it's also the global dead code elimination
| > | stuff, and a variety of other optimizations.  For example, the LLVM dead
| > | argument eliminator and IP constant prop passes are able to do a lot of
| > | nice things to code, but only if it is marked with internal linkage.
| >
| > But what you need is not "internal linkage" (i.e. declaring  the
| > functions or objects as "static"), but the notion of "regarless of the
| > actual linkage of this entity, it is referenced only in this
| > translation unit and cannot appear somewhere else".
| 
| That is exactly what I'm talking about.  I'm very confused here.  In LLVM,
| the source-level notion of internal linkage is very different from the
| LLVM notion of internal linkage.

But then use a difference terminology if you don't want to confuse
yourself  (or a C++ programmer talking with you).  A C++ programmer knows
what "static" and "internal linkage" means in C++.  If you change
those phrases to mean something different from what they do in a C++
programme source, you better accurately state their meanings.  Using a
different word is far better.

|  I haven't change the C++ front-end at
| all in this respect, just the LLVM code that gets generated.  As such,
| there is no way that name lookup could be effected.

It depends on what form of inputs you generate your code from. 

[...]

| > I strongly advise against a naive approach to this issue, that would
| > not have an understanding of unnamed namespace semantics, C++ name
| > lookup rules and exported templates.
| 
| Again, I emphasize that the LLVM treatment of this results in
| _dramatically_ better code, and has zero semantic implications since
| 'export' has not been implemented yet.

As I just showed, "export" is not needed to illustrate the fundamental
semantic problem.  I understand you rank speed over correctness, but
we cannot afford transmuting people's programs in a way that changes
their meanings. 

| > | Also, you can't mark a class 'static' (making the member
| > | functions, vtables, rtti info, etc all internal).
| >
| > So what?  What you want is not "static" but a way to say "this thing
| > is used only in this translation unit".
| 
| _exactly_, which is something that you cannot do without unnamed
| namespaces!

Again, as I said earlier and illustrated above, functions declared
in an unnamed namespace can "escape", so an unnamed namespace does not
do what you  think it does.

|  For example, if a (nonvirtual) method is only called from one
| call site, and its class is in an anonymous namespace, it _should be
| inlined_ into that call site, (almost) regardless of how big it is.
| There are many other examples of this kind of thing.  How do you achieve
| this without anonymous namespaces behaving sanely?

But an unnamed namespace does not guarantee that an entity defined in it
does not escape!  See the example above.
 
| > | That's fine, I just told you how we _implemented it_.
| >
| > And I just asked you if you implemented the rest of the language.
| > Because what it important is not what you implement in isolation, but
| > the interaction with the rest of the language.  I just explained you
| > how it leads to incorrect translation of conforming codes.
| 
| Transforming objects in unnamed namespaces to use LLVM internal linkage
| cannot cause any regressions from an unmodified G++ front-end.  In the
| future, the addition of export may not make this true, but if so, it can
| be dealt with then.  Also, it does not appear to me that export will be
| added to g++ anytime in the near future.  I find it ridiculous that you
| advocate non-LLVM G++ to generate pessimal code in the meantime.

What is ridiculous is you not understanding how unnamed namespace and
C++ name lookup rules work and saying I'm ridiculous when I'm
telling you that your statement does not match C++ rules -- not
mentioning your use of "static" and "internal linkage" in totally
different and undefined way.  You're free to implement whatever you
like in your research compiler. What, however, is not correct is your
using "static" and "internal linkage" in very sneaky ways to mean
totally different things in a discussion where people are already
confused about the semantics of unnamed namespaces and static.

And, I'm not advocating people generate pessimal code.  I'm telling
people that they should teach the inliner about unnamed namespaces
instead of transmuting meanings of well-defined codes.  But of course,
if the only thing you measure is speed and you rank it over
correctness, you may not understand what I'm saying.

-- Gaby


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]