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


341. extern "C" namespace member function versus global variable

Section: 9.11  [dcl.link]     Status: C++11     Submitter: Steve Adamczyk     Date: 1 Mar 2002

[Voted into the WP at the November, 2010 meeting.]

Here's an interesting case:

  int f;
  namespace N {
    extern "C" void f () {}
  }
As far as I can tell, this is not precluded by the ODR section (6.3 [basic.def.odr]) or the extern "C" section (9.11 [dcl.link]). However, I believe many compilers do not do name mangling on variables and (more-or-less by definition) on extern "C" functions. That means the variable and the function in the above end up having the same name at link time. EDG's front end, g++, and the Sun compiler all get essentially the same error, which is a compile-time assembler-level error because of the duplicate symbols (in other words, they fail to check for this, and the assembler complains). MSVC++ 7 links the program without error, though I'm not sure how it is interpreted.

Do we intend for this case to be valid? If not, is it a compile time error (required), or some sort of ODR violation (no diagnostic required)? If we do intend for it to be valid, are we forcing many implementations to break binary compatibility by requiring them to mangle variable names?

Personally, I favor a compile-time error, and an ODR prohibition on such things in separate translation units.

Notes from the 4/02 meeting:

The working group agreed with the proposal. We feel a diagnostic should be required for declarations within one translation unit. We also noted that if the variable in global scope in the above example were declared static we would still expect an error.

Relevant sections in the standard are 9.11 [dcl.link] paragraph 6 and 6.6 [basic.link] paragraph 9. We feel that the definition should be written such that the entities in conflict are not "the same entity" but merely not allowed together.

Additional note (September, 2004)

This problem need not involve a conflict between a function and a variable; it can also arise with two variable declarations:

    int x;
    namespace N {
        extern "C" int x;
    }

Proposed resolution (March, 2008):

Change 9.11 [dcl.link] paragraph 6 as follows:

At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function. Two declarations for an object with C language linkage with the same name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same object. A function or object with C linkage shall not be declared with the same name (6.1 [basic.pre]) as an object or reference declared in global scope, unless both declarations denote the same object; no diagnostic is required if the declarations appear in different translation units. [Note: because of the one definition rule (6.3 [basic.def.odr]), only Only one definition for a function or object with C linkage may appear in the program (see 6.3 [basic.def.odr]); that is, implies that such a function or object must not be defined in more than one namespace scope. For example,

    int x;
    namespace A {
      extern "C" int f();
      extern "C" int g() { return 1; }
      extern "C" int h();
      extern "C" int x();               // ill-formed: same name as global-scope object x
    }

    namespace B {
      extern "C" int f();               // A::f and B::f refer
                                        // to the same function
      extern "C" int g() { return 1; }  // ill-formed, the function g
                                        // with C language linkage
                                        // has two definitions
    }

    int A::f() { return 98; }           // definition for the function f
                                        // with C language linkage
    extern "C" int h() { return 97; }
                                        // definition for the function h
                                        // with C language linkage
                                        // A::h and ::h refer to the same function

end note]

Notes from the September, 2008 meeting:

It should also be possible to declare references with C name linkage (although the meaning the first sentence of 9.11 [dcl.link] paragraph 1 with respect to the meaning of such a declaration is not clear), which would mean that the changed wording should refer to declaring “the same entity” instead of “the same object.” The formulation here would probably benefit from the approach currently envisioned for issues 570 and 633, in which “variable” is defined as being either an object or a reference.

Proposed resolution (February, 2010):

Change 9.11 [dcl.link] paragraph 6 as follows:

At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function. Two declarations for an object or reference with C language linkage with the same name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same object or reference. An entity with C language linkage shall not be declared with the same name as an entity in global scope, unless both declarations denote the same object or reference; no diagnostic is required if the declarations appear in different translation units. [Note: because of the one definition rule (6.3 [basic.def.odr]), only Only one definition for a function or object an entity with C linkage may appear in the program (see 6.3 [basic.def.odr]); that is, implies that such a function or object an entity must not be defined in more than one namespace scope. end note] For example, [Example:

  int x;
  namespace A {
    extern "C" int f();
    extern "C" int g() { return 1; }
    extern "C" int h();
    extern "C" int x();               // ill-formed: same name as global-scope object x
  }

  namespace B {
   extern "C" int f();                // A::f and B::f refer
                                      // to the same function
   extern "C" int g() { return 1; }   // ill-formed, the function g
                                      // with C language linkage
                                      // has two definitions
  }

  int A::f() { return 98; }           // definition for the function f
                                      // with C language linkage
  extern "C" int h() { return 97; }
                                      // definition for the function h
                                      // with C language linkage
                                      // A::h and ::h refer to the same function

end note example]

Additional note (February, 2010):

The proposed wording above does not cover the case where two different entities with C linkage are declared in different namespaces, only the case where one of the entities is in global scope.

Proposed resolution (August, 2010):

Change 9.11 [dcl.link] paragraph 6 as follows:

At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function. Two declarations for an object a variable with C language linkage with the same name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same object variable. An entity with C language linkage shall not be declared with the same name as an entity in global scope, unless both declarations denote the same entity; no diagnostic is required if the declarations appear in different translation units. A variable with C language linkage shall not be declared with the same name as a function with C language linkage (ignoring the namespace names that qualify the respective names); no diagnostic is required if the declarations appear in different translation units. [Note: because of the one definition rule (6.3 [basic.def.odr]), only Only one definition for a function or object an entity with a given name with C language linkage may appear in the program (see 6.3 [basic.def.odr]); that is, implies such a function or object an entity must not be defined in more than one namespace scope. end note] For example, [Example:

  int x;
  namespace A {
    extern "C" int f();
    extern "C" int g() { return 1; }
    extern "C" int h();
    extern "C" int x();               // ill-formed: same name as global-scope object x
  }

  namespace B {
    extern "C" int f();               // A::f and B::f refer
                                      // to the same function
    extern "C" int g() { return 1; }  // ill-formed, the function g
                                      // with C language linkage
                                      // has two definitions
  }

  int A::f() { return 98; }           // definition for the function f
                                      // with C language linkage
  extern "C" int h() { return 97; }
                                      // definition for the function h
                                      // with C language linkage
                                      // A::h and ::h refer to the same function

end note example]

[Note to editor: please consider reformatting the comments in the example.]