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

2023-02-07


2372. Incorrect matching rules for block-scope extern declarations

Section: 6.6  [basic.link]     Status: CD5     Submitter: Chen Fuxingi     Date: 2017-12-17

[Accepted as a DR at the February, 2019 meeting.]

According to 6.6 [basic.link] paragraph 6,

The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration have linkage. If there is a visible declaration of an entity with linkage having the same name and type, ignoring entities declared outside the innermost enclosing namespace scope, the block scope declaration declares that same entity and receives the linkage of the previous declaration. If there is more than one such matching entity, the program is ill-formed. Otherwise, if no matching entity is found, the block scope entity receives external linkage.

The requirement that the entities have the same type does not cover all cases that it should. Consider an example like:

  static int a[3];
  void g() {
    printf("%p\n", (void*)a);
    extern int a[];
    printf("%p\n", (void*)a);
  }

According to the cited wording, the block-scope declaration of a does not match the namespace scope declaration because int[] and int[3] are different types, thus the first reference to a refers to the static variable while the second one refers to a variable a defined in some other translation unit. This is clearly not intended, and current implementations treat both references as referring to the static variable.

Notes from the October, 2018 teleconference:

CWG agreed with the direction and noted that a similar situation occurs with extern "C" functions.

Proposed resolution (November, 2018):

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

The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration have linkage. If there is a visible declaration of an entity with linkage having the same name and type, ignoring entities declared outside the innermost enclosing namespace scope, such that the block scope declaration would be a (possibly ill-formed) redeclaration if the two declarations appeared in the same declarative region, the block scope declaration declares that same entity and receives the linkage of the previous declaration. If there is more than one such matching entity, the program is ill-formed. Otherwise, if no matching entity is found, the block scope entity receives external linkage. If, within a translation unit, the same entity is declared with both internal and external linkage, the program is ill-formed. [Example:

  static void f();
  extern "C" void h();
  static int i = 0;      // #1
  void g() {
    extern void f();     // internal linkage
    extern void h();     // C language linkage

    int i;               // #2: i has no linkage
    {
      extern void f();   // internal linkage
      extern int i;      // #3: external linkage, ill-formed
    }
  }

Without the declaration at line #2, the declaration at line #3 would link with the declaration at line #1. Because the declaration with internal linkage is hidden, however, #3 is given external linkage, making the program ill-formed. —end example]