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