This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 114a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-04-18


2059. Linkage and deduced return types

Section: 9.2.9.7  [dcl.spec.auto]     Status: CD5     Submitter: Richard Smith     Date: 2014-12-15

[Accepted as a DR at the March, 2018 (Jacksonville) meeting.]

Use of function return type deduction makes it possible to define functions whose return type is a type without linkage. Although 6.6 [basic.link] paragraph 8 permits such a usage if the function is defined in the same translation unit as it is used, it may be helpful to consider changing the overall rules regarding the use of types with internal or no linkage. As an example, the following example permits access to a local static variable that has not been initialized:

  auto f() {
    static int n = 123;
    struct X { int &f() { return n; } };
    return X();
  }
  int &r = decltype(f())().f();

Notes from the February, 2016 meeting:

CWG agreed that the current rule in 6.6 [basic.link] paragraph 8 is unneeded; the ODR already prohibits use of an entity that is not defined in the current translation unit and cannot be defined in a different translation unit.

Proposed resolution (November, 2017)

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 external linkage unless

[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 must be defined in the translation unit if it is odr-used. Also note that classes Classes with linkage may contain members whose types do not have linkage, and that typedef. Typedef names are ignored in the determination of whether a type has linkage. —end note] [Example:

  template <class 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; A cannot be named in the another translation unit
    i(ba, a);             // OK
  }

end example]