Topic: Static typenames (was C++ Language Extensions)


Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Thu, 1 Jul 1993 17:57:06 GMT
Raw View
In article <C9GFFG.8Hv@sugar.NeoSoft.COM> daniels@NeoSoft.com (Brad Daniels) writes:
>In article <1993Jun30.161250.19398@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>>In article <C9EuJz.FCK@sugar.NeoSoft.COM> daniels@NeoSoft.com (Brad Daniels) writes:
>>
>> My concept of linkage: there are two way identifiers
>>are bound in a language: using scope/hiding etc and using linkage.
>>
>> Linkage is a mechanism that is used to
>>account for separate compilation. The concept only applies to
>>things defined in file scope. Because only they can have the
>>same meaning in two separate compilation units.
>
>Going back and reading the ANSI C definition of linkage, I see that you
>are right.  I had somehow gotten the idea that block-scope static object
>identifiers had internal linkage, which they do not.  Actually, it's fairly
>easy to see how I got confused

 Sure it is: the ARM agrees with you. In C++ everything
supposedly has linkage. My account above is only my concept,
others are possible.

>Both block-scope static object identifiers
>and functions like the above require actual storage and some kind of internal
>identifier to indicate that storage, in exactly the same way as a file-scope
>object or function with internal linkage requires such an identifier.  I
>was confusing this internal identifier (which may be nothing more than a
>pointer to part of a parse tree somewhere in a code generator) with the
>actual symbol defined in the program.

 No, your view is not wrong at all, just different: you are
certainly no more confused than the ARM. <grin>
>
>Further confusing the matter is the fact that file scope typedef and
>struct names have no linkage in ANSI C, further reinforcing the misconception
>that linkage refers solely to physical storage.  Actually, as I think about it,
>the entire concept of internal linkage is rather ill-defined.  Is it really
>needed?

 Good question. My concept is that certain things
might have linkage across compilation units (external linkage),
and 'internal' just means that they actually dont (have external
linkage). For other things, the question never arises because
cant have external linkage, so its neither external linkage nor
internal but 'no linkage': which means the same more or
less as 'internal'. So the ARM only has 'internal' and 'external',
and no concept of 'no linkage'.

>It seems to me that scoping rules take care of all the things
>internal linkage is intended to achieve.  Is it possible that the C++ standard
>is moving towards having only external and no linkage, but just to confuse
>matters, someone decided to call no linkage "internal linkage"?

 Could be. Everything is scoped, but somethings
have external linkage as well.
>
>What difference would there be between a file-scope object with no linkage
>and one with internal linkage?

 The one with internal linkage might be 'converted' to
have external linkage: the one with no linkage cant be.

 There's a vague concept that the 'internal' symbols
at file scope are 'nested' in a greater 'external/global' scope:

 namespace program {
  int x;
  int f();
  namespace translation_unit1 {
   int z;
  }
  namespace translation_unit2 {
   int z'
  }
 }

although this isnt entirely accurate.

>E.g., in C, is there any difference between
>the visibility of a file-scope struct identifier and that of a static
>variable?

 not really. (Actually, yes, there is: because 'struct'
names live in their own tag-namespace, but I'll ignore that :-)

>If internal linkage were redefined simply to refer to any object
>which is not visible outside of the compilation unit, then it makes sense
>to eliminate the concept of "no linkage".

 Yes, perhaps. But perhaps it makes sense, because
if a symbols has linkage you have to answer 'external' or 'internal',
whereas if a symbol does not have linkage then you cannot even
ask "does this name have external or internal linkage" because
its not a well formed question.

 So its perhaps a matter of what is easier to explain,
and what words are best to write into the Standard.
>
>The more I think about this concept, the more I think this must be the
>intent.  The concept of "no linkage" is redundant given the visibility
>attributes of scope.  The confusion comes from trying to apply the
>ANSI C definition of internal linkage to C++, a practice which the working
>document encourages by not defining the terms internal linkage and external
>linkage explicitly (all it does is list the things which have each type
>of linkage.)

 How do you explain:

File 1     File 2
struct X { int x; }   struct X { long x; } // error
static float f;    static float f; // error
g() { extern auto int k; } // error

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,      CSERVE:10236.1703
        6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
        NSW 2131, AUSTRALIA




Author: daniels@NeoSoft.com (Brad Daniels)
Date: Thu, 1 Jul 1993 19:16:18 GMT
Raw View
In article <1993Jul1.175706.25199@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
...
> How do you explain:
>
>File 1     File 2
>struct X { int x; }   struct X { long x; } // error
>static float f;    static float f; // error
>g() { extern auto int k; } // error

I was following you up to this point, but the relevance of the example
eludes me.  The declarations of f are not in error, because both have
internal linkage under any current definition of the term.  The declarations
of X have external linkage in C++, so of course they conflict.  Actually,
there are some waffle words (I forget the exact section) which imply that
X can have internal linkage in the particular context above.  The g()
part I don't understand at all.  The only error I see is the conflict in
explicit storage class types.  Both ANSI C and the working document
discuss the case of extern at block scope.

- Brad
--
Brad Daniels   |  "Let others praise ancient times.
daniels@neosoft.com  |   I am glad I was born in these."
I don't work for NeoSoft, and | - Ovid (43 B.C. - 17 A.D)
don't speak for my employer. |




Author: patel@shell.com (Amit Patel)
Date: Tue, 29 Jun 1993 16:07:17 GMT
Raw View
In article <1993Jun26.175517.16100@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:

|
|    The change with respect to classes is intentional.
|    The change to not having 'no linkage' might have been
|    an ommission.
|
|     f() {
|      float x;
|     };
|
|    Should 'x' really have internal linkage?
|
|    There is a proposal to re-introduce 'no linkage'. I feel inclined
|    to accept this. Any comments?
|
|

I have a question with respect to name mangling with no linkage in the
language:


=== file1.cc ===   === file2.cc ===
/* static */    /* static */
enum Color { red, green, blue }; enum Color { yellow, cyan, magenta };

void f(Color x)    void f(Color x)
{     {
   printf("Hey!\n");      printf("Goodbye, world!\n");
}     }
================   ================

What do we do about mangling function names with the types of the
arguments?  Would these two not mangle to the same function, and
introduce a linking error?

  Confused,

   Amit

--
--
Amit J Patel, patel@shell.com




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 29 Jun 1993 21:43:30 GMT
Raw View
In article <PATEL.93Jun29110718@aeroflot.shell.com> patel@shell.com (Amit Patel) writes:
>In article <1993Jun26.175517.16100@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>
>|
>|    The change with respect to classes is intentional.
>|    The change to not having 'no linkage' might have been
>|    an ommission.
>|
>|     f() {
>|      float x;
>|     };
>|
>|    Should 'x' really have internal linkage?
>|
>|    There is a proposal to re-introduce 'no linkage'. I feel inclined
>|    to accept this. Any comments?
>
>I have a question with respect to name mangling with no linkage in the
>language:
>
>
>=== file1.cc ===   === file2.cc ===
>/* static */    /* static */
>enum Color { red, green, blue }; enum Color { yellow, cyan, magenta };
>
>void f(Color x)    void f(Color x)
>{     {
>   printf("Hey!\n");      printf("Goodbye, world!\n");
>}     }
>================   ================
>
>What do we do about mangling function names with the types of the
>arguments?  Would these two not mangle to the same function, and
>introduce a linking error?

 J Stephen Adamczyk proposes in WG21/N0282
that the following have no linkage:

 Local variables.
 Local types.
 All members of local types.
 Non-class types.
 Enumeration constants.
 Function and template parameters.

I'm sure that enum types must be counted as class types here:
for exactly the reason you illustrate above.

(Whats a non-class type then? A typedef?
Note that a 'pointer' type is a non-class type: but it doesnt
have a 'name' so the issue of linkage doesnt arise except through
a typedef.)

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,      CSERVE:10236.1703
        6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
        NSW 2131, AUSTRALIA




Author: barmar@think.com (Barry Margolin)
Date: 30 Jun 1993 02:46:20 GMT
Raw View
In article <PATEL.93Jun29110718@aeroflot.shell.com> patel@shell.com (Amit Patel) writes:
>=== file1.cc ===   === file2.cc ===
>/* static */    /* static */
>enum Color { red, green, blue }; enum Color { yellow, cyan, magenta };
>
>void f(Color x)    void f(Color x)
>{     {
>   printf("Hey!\n");      printf("Goodbye, world!\n");
>}     }
>================   ================
>
>What do we do about mangling function names with the types of the
>arguments?  Would these two not mangle to the same function, and
>introduce a linking error?

A function that takes an argument or returns a value of a static type
wouldn't be useful outside that compilation unit.  Consider: how could it
be called from another compilation unit, since the caller can't declare an
object to pass as the argument, nor even prototype the function.

Thus, a function whose signature includes a static type should
automatically be static as well.  Therefore, there can't be any linkage
conflicts.

--
Barry Margolin
System Manager, Thinking Machines Corp.

barmar@think.com          {uunet,harvard}!think!barmar




Author: daniels@NeoSoft.com (Brad Daniels)
Date: Tue, 29 Jun 1993 19:49:54 GMT
Raw View
In article <PATEL.93Jun29110718@aeroflot.shell.com> patel@shell.com (Amit Patel) writes:
>I have a question with respect to name mangling with no linkage in the
>language:
>
>
>=== file1.cc ===   === file2.cc ===
>/* static */    /* static */
>enum Color { red, green, blue }; enum Color { yellow, cyan, magenta };
>
>void f(Color x)    void f(Color x)
>{     {
>   printf("Hey!\n");      printf("Goodbye, world!\n");
>}     }
>================   ================

Cute example.  The above is illegal according to the current language
"definition" by the "one definition" rule.  Color has been defined in
two different ways.  The extension I originally proposed did not include
static enumerators, though it could just as easily, I suppose, since you
can encounter the same problem with static classes.

I was talking about internal linkage, which is the issue in the above
example, while the note you responded to was talking about another issue,
that being the fact that a local variable has internal linkage rather
than no linkage at all.  In the absence of namespace resolution operators
to allow one to access local variables, they have all the attributes of
variables with no linkage, regardless of the nomenclature used in the
standard, so I suppose the whole "no linkage" issue is really more about
the semantics of the standard rather than the semantics of the language...

Anyway, the most sensible approach to the above would be to disallow
functions having external linkage from having arguments whose types
have internal linkage.  You don't need a similar restriction for class
members, since that's already covered under the "one definition" rule.
(I.e. if a class has a member of static type, its declaration in any
module will always differ from its definition in every other, since each
module will have a unique definition of the static type.)

- Brad
--
Brad Daniels   |  "Let others praise ancient times.
daniels@neosoft.com  |   I am glad I was born in these."
I don't work for NeoSoft, and | - Ovid (43 B.C. - 17 A.D)
don't speak for my employer. |




Author: daniels@NeoSoft.com (Brad Daniels)
Date: Wed, 30 Jun 1993 01:23:58 GMT
Raw View
In article <1993Jun29.214330.5348@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
...
> J Stephen Adamczyk proposes in WG21/N0282
>that the following have no linkage:
>
> Local variables.
> Local types.
> All members of local types.
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Non-class types.
> Enumeration constants.
> Function and template parameters.
>
>I'm sure that enum types must be counted as class types here:
>for exactly the reason you illustrate above.

There's also a problem with saying members of local types have no linkage.
Consider:

void bar() {
    class localC1 {
    public:
 localC1() {}
 void out() { cout << "hello\n"; }
    } c1;
    class localC2 {
    public:
 static void foo(localC1* b, void localC1::*f()) { b->f(); }
    };
    localC2::foo(&c1, localC1::out);
}

I'm not on a system with a compiler, and I don't have up-to-date docs
handy, so I'm not positive on my pointer to member function syntax,
but you get the idea.

In the above, out is a member of localC1, but the call to localC2::foo
needs a pointer to it, so it must have some linkage, in this case internal.
The same trick can be played with local static member functions and with
local static data members.  Local nonstatic data members can always have
no linkage, and local nonstatic member functions can have no linkage if
they are never passed as a reference.

- Brad
--
Brad Daniels   |  "Let others praise ancient times.
daniels@neosoft.com  |   I am glad I was born in these."
I don't work for NeoSoft, and | - Ovid (43 B.C. - 17 A.D)
don't speak for my employer. |




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Wed, 30 Jun 1993 16:12:50 GMT
Raw View
In article <C9EuJz.FCK@sugar.NeoSoft.COM> daniels@NeoSoft.com (Brad Daniels) writes:
>Consider:
>
>void bar() {
>    class localC1 {
>    public:
> localC1() {}
> void out() { cout << "hello\n"; }
>    } c1;
>    class localC2 {
>    public:
> static void foo(localC1* b, void localC1::*f()) { b->f(); }
>    };
>    localC2::foo(&c1, localC1::out);
>}
>
>In the above, out is a member of localC1, but the call to localC2::foo
>needs a pointer to it, so it must have some linkage, in this case internal.

 Why?

 My concept of linkage: there are two way identifiers
are bound in a language: using scope/hiding etc and using linkage.

 Linkage is a mechanism that is used to
account for separate compilation. The concept only applies to
things defined in file scope. Because only they can have the
same meaning in two separate compilation units.

 So there is no problem in your example. First one
says: does it have linkage or not? Then, if it has linkage,
one decides on either internal or external.

 Now I'll show you are contentious example:

 class X {
  inline int f() { static int x; }
 }

The function 'f' has internal linkage. But, the ODR requires
only one definition of a class, and that applies somehow to
its members. In particular, various esteemed committee members
have argued that 'f' above must have external linkage,
despite being inline (i.e. the ARM is wrong on this issue).

Another argument I've heard is that inline members may not
have static data in them at all.

The problem is that really in *this* case, 'x' requires
**external** linkage. Because, otherwise, in some sense,
'f' will break the ODR, whether it has internal linkage or not.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,      CSERVE:10236.1703
        6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
        NSW 2131, AUSTRALIA




Author: daniels@NeoSoft.com (Brad Daniels)
Date: Wed, 30 Jun 1993 21:52:28 GMT
Raw View
In article <1993Jun30.161250.19398@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>In article <C9EuJz.FCK@sugar.NeoSoft.COM> daniels@NeoSoft.com (Brad Daniels) writes:
>>Consider:
>>
>>void bar() {
>>    class localC1 {
>>    public:
>> localC1() {}
>> void out() { cout << "hello\n"; }
>>    } c1;
>>    class localC2 {
>>    public:
>> static void foo(localC1* b, void localC1::*f()) { b->f(); }
>>    };
>>    localC2::foo(&c1, localC1::out);
>>}
>>
>>In the above, out is a member of localC1, but the call to localC2::foo
>>needs a pointer to it, so it must have some linkage, in this case internal.
>
> Why?
>
> My concept of linkage: there are two way identifiers
>are bound in a language: using scope/hiding etc and using linkage.
>
> Linkage is a mechanism that is used to
>account for separate compilation. The concept only applies to
>things defined in file scope. Because only they can have the
>same meaning in two separate compilation units.

Going back and reading the ANSI C definition of linkage, I see that you
are right.  I had somehow gotten the idea that block-scope static object
identifiers had internal linkage, which they do not.  Actually, it's fairly
easy to see how I got confused:  Both block-scope static object identifiers
and functions like the above require actual storage and some kind of internal
identifier to indicate that storage, in exactly the same way as a file-scope
object or function with internal linkage requires such an identifier.  I
was confusing this internal identifier (which may be nothing more than a
pointer to part of a parse tree somewhere in a code generator) with the
actual symbol defined in the program.

Further confusing the matter is the fact that file scope typedef and
struct names have no linkage in ANSI C, further reinforcing the misconception
that linkage refers solely to physical storage.  Actually, as I think about it,
the entire concept of internal linkage is rather ill-defined.  Is it really
needed?  It seems to me that scoping rules take care of all the things
internal linkage is intended to achieve.  Is it possible that the C++ standard
is moving towards having only external and no linkage, but just to confuse
matters, someone decided to call no linkage "internal linkage"?

What difference would there be between a file-scope object with no linkage
and one with internal linkage?  E.g., in C, is there any difference between
the visibility of a file-scope struct identifier and that of a static
variable?  If internal linkage were redefined simply to refer to any object
which is not visible outside of the compilation unit, then it makes sense
to eliminate the concept of "no linkage".

The more I think about this concept, the more I think this must be the
intent.  The concept of "no linkage" is redundant given the visibility
attributes of scope.  The confusion comes from trying to apply the
ANSI C definition of internal linkage to C++, a practice which the working
document encourages by not defining the terms internal linkage and external
linkage explicitly (all it does is list the things which have each type
of linkage.)

- Brad
--
Brad Daniels   |  "Let others praise ancient times.
daniels@neosoft.com  |   I am glad I was born in these."
I don't work for NeoSoft, and | - Ovid (43 B.C. - 17 A.D)
don't speak for my employer. |