Title
Types without linkage in declarations
Status
cd2
Section
6.6 [basic.link]
Submitter
John Spicer

Created on 2008-12-23.00:00:00 last changed 171 months ago

Messages

Date: 2009-07-15.00:00:00

[Voted into WP at July, 2009 meeting.]

Date: 2009-03-15.00:00:00

Proposed resolution (March, 2009):

Change 6.6 [basic.link] paragraph 8 as follows:

...A type without linkage shall not be used as the type of a variable or function with linkage, unless

  • the variable or function has extern "C" linkage (9.11 [dcl.link]), or

  • the type without linkage was named using a dependent type (13.8.3.2 [temp.dep.type]) the variable or function is not used (6.3 [basic.def.odr]) or is defined in the same translation unit.

[Note: in other words, a type without linkage contains a class or enumeration that cannot be named outside its translation unit. An entity with external linkage declared using such a type could not correspond to any other entity in another translation unit of the program and thus is not permitted must be defined in the translation unit if it is used. Also note that classes with linkage may contain members whose types do not have linkage, and that typedef names are ignored in the determination of whether a type has linkage. —end note] [Example:

    void f() {
      struct A { int x; };    // no linkage
      extern A a;             // ill-formed
      typedef A B;
      extern B b;             // ill-formed
    }

end example]

[Example:

    template <class T> struct A {
      // in A<X>, the following is allowed because the type with no linkage
      // X is named using template parameter T.
      friend void f(A, T){}
    };

    template <class T> void g(T t) {
      A<T> at;
      f(at, t);
    }

    int main() {
      class X {} x;
      g(x);
    }


    template <typename T> struct B {
        void g(T){}
        void h(T);
        friend void i(B, T){}
    };

    void f() {
        struct A { int x; };  // no linkage
        A a = {1};
        B<A> ba;              // declares B<A>::g(A) and B<A>::h(A)
        ba.g(a);              // OK
        ba.h(a);              // error: B<A>::h(A) not defined in the translation unit
        i(ba, a);             // OK
    }

end example]

[Drafting note: issue 527 also changes part of the same text.]

Date: 2008-06-15.00:00:00

Paper N2657, adopted at the June, 2008 meeting, removed the prohibition of local and unnamed types as template arguments. As part of the change, 6.6 [basic.link] paragraph 8 was modified to read,

A type without linkage shall not be used as the type of a variable or function with linkage, unless

  • the variable or function has extern "C" linkage (9.11 [dcl.link]), or

  • the type without linkage was named using a dependent type (13.8.3.2 [temp.dep.type]).

Because a type without linkage can only be named as a dependent type, there are still some potentially useful things that cannot be done:

    template <class T> struct A {
      friend void g(A, T);  // this can't be defined later
      void h(T);  // this cannot be explicitly specialized
    };

    template <class T> void f(T) {
      A<T> at;
      g(at, (T)0);
    }

    enum { e };

    void g(A<decltype(e)>, decltype(e)){}  // not allowed

    int main() {
      f(e);
    }

These deficiencies could be addressed by allowing types without linkage to be used as the type of a variable or function, but with the requirement that any such entity that is used must also be defined in the same translation unit. This would allow issuing a compile-time, instead of a link-time, diagnostic if the definition were not provided, for example. It also seems to be easier to implement than the current rules.

History
Date User Action Args
2010-03-29 00:00:00adminsetstatus: wp -> cd2
2009-11-08 00:00:00adminsetstatus: dr -> wp
2009-08-03 00:00:00adminsetmessages: + msg2226
2009-08-03 00:00:00adminsetstatus: ready -> dr
2009-03-23 00:00:00adminsetmessages: + msg1884
2009-03-23 00:00:00adminsetstatus: open -> ready
2008-12-23 00:00:00admincreate