Static linkage and anonymous namespace

Mark Mitchell mark@markmitchell.com
Mon Aug 31 08:33:00 GMT 1998


>>>>> "Martin" == Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de> writes:

    >> But why can't we just make the definitions have internal
    >> linkage if they're in an anonymous namespace?  Why do we need
    >> to introduce the TREE_PRIVATE bit?  In other words, at some
    >> point the compiler decides whether to make things have internal
    >> or external linkage.  Why doesn't it just use the DECL_CONTEXT
    >> (recursively looking at parent contexts) to see what linkage
    >> the thing should get?

    Martin> Good questions. As far as I can tell, there are two
    Martin> reasons:

    Martin> 1. Not all members of an anonymous namespace can have
    Martin> internal linkage. Specifically, foo in

    Martin>    namespace{ extern "C" foo(){} }

    Martin>    can be called from other translation units. This is
    Martin> because of the way anonymous namespaces and C linkage are
    Martin> defined. Maybe this is really a defect, maybe this is
    Martin> intentional.

I think the latter.  But, it is in any case easy to check for
explicitly. 

    Martin> 2. Some members of named namespaces also get this internal
    Martin> linkage.  Given

    Martin>    namespace { struct Foo{}; }

    Martin>    we get this on

    Martin>    void print(Foo&){} std::vector<Foo> vfoo;

    Martin>    Other translations can't use these objects/functions,
    Martin> since they can't provide the parameters. Not making them
    Martin> internal means to risk linkage problems again, if some
    Martin> other translation unit has the same sequence of tokens.

Ah, I see what you're up to.  But, I think you've gone too far!  We
have:

  A name declared in a namespace scope without a storage-class-specifier
  has external linkage unless it has internal linkage because of a  pre-
  vious  declaration  and  provided  it  is not declared const.

and:

  3 A  name  having namespace scope (_basic.scope.namespace_) has internal
  linkage if it is the name of

  --an  object,  reference,  function  or  function  template  that   is

    explicitly declared static or,

  --an object or reference that is explicitly declared const and neither
    explicitly declared extern nor previously declared to have  external
    linkage; or

  --a data member of an anonymous union.

  4 A  name  having namespace scope has external linkage if it is the name
  of

  --an object or reference, unless it has internal linkage; or

  --a function, unless it has internal linkage; or

  --a named class (clause _class_), or an unnamed  class  defined  in  a
    typedef  declaration  in  which  the  class has the typedef name for
    linkage purposes (_dcl.typedef_); or

  --a named enumeration (_dcl.enum_), or an unnamed enumeration  defined
    in  a  typedef  declaration in which the enumeration has the typedef
    name for linkage purposes (_dcl.typedef_); or

  --an enumerator belonging to an enumeration with external linkage; or

  --a template, unless it is a function template that has internal link-
    age (clause _temp_); or

  --a  namespace  (_basic.namespace_),  unless  it is declared within an
    unnamed namespace.

The rule you're think of is probably:

  A name with no linkage (notably, the name of a class or enu-
  meration declared in a local scope (_basic.scope.local_)) shall not be
  used to declare an entity with linkage.

Other examples that fall under this rule are:

  typedef enum { a } *EP; 
  template <class T> void f(T);
  void g()
  {
    EP ep;
    f(*EP); // Try to create template instantiation with external
            // linkage, involving unnamed type.
  } 

This falls under, more specifically:

  local  type, a type with no linkage, an unnamed type or a type com-
  pounded from any of these types shall  not  be  used  as  a  template-
  argument for a template type-parameter. 

So, the example you give is not legal C++.  Therefore, I think we
should do the more obvious thing: give it external linkage, as
mandated by the standard.  Of course, you can use the name-mangling
algorithm to issue errors on such declarations as you point out: if
the declaration has external linkage and involves one of these bogus
types, then give an error.  This would solve the general problem of
using types with internal/no linkage in declarations with external
linkage.

So, I think I stand by my earlier positition.  In summary:

  o At declaration time, calculuate linkage, according to rules above.
  o If motivated, add error-checking to name-mangling algorithm.
  o Do *not* give `void print(Foo&){} std::vector<Foo> vfoo'
    internal linkage; it's just errorneous code so you shouldn't
    be working that hard.
  o Do *not* add the TREE_PRIVATE bit.

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com



More information about the Gcc-patches mailing list