Search code examples
c++c++11linkageone-definition-rule

ODR and internal linkage


Assume that I have two compilation units in a single program, each of which declares a non-inline function with identical signatures, but differing in implementation, such as

// a.cpp
namespace internal {
    int foo(int a) {
        return a+1;
    }
}

int main() {
}

and

// b.cpp
namespace internal {
    int foo(int b) {
        return b+2;
    }
}

Compiling/linking this (g++ 4.8.3 with -std=c++11), I get an error

b.cpp:(.text+0x0): multiple definition of `internal::foo(int)'

which is rather expected, since, as far as I understand, this is simply a violation of the one definition rule:

One and only one definition of every non-inline function or variable that is odr-used (see below) is required to appear in the entire program (including any standard and user-defined libraries).

Now, changing the namespace internal into an unnamed namespace, the error goes away. Intuitively, this make sense to me, since I'm changing the function from external to internal linkage:

Any of the following names declared at namespace scope have external linkage unless the namespace is unnamed or is contained within an unnamed namespace (since C++11): variables and functions not listed above (that is, functions not declared static [...]) ...

and

[A]ll names declared in unnamed namespace or a namespace within an unnamed namespace, even ones explicitly declared extern, have internal linkage.

However, I was unable to find anything in the one definition rule that exempts functions with internal linkage from it. Therefore, my question is: Is my intuitive reasoning correct, or am I still violating the one definition rule with functions that have internal linkage (and the compiler/linker just doesn't report it anymore)? Additionally, where does the standard (or cppreference.com :)) say whether or not it is ok?


Solution

  • n4713

    §6.5 Program and linkage [basic.link]

    A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:

    (2.1) — When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.

    (2.2) — When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.

    — When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.

    This basically says that (in the case of unnamed namespaces) the name foo from a.cpp and the name foo from b.cpp each refer to different entities. So you don't have two definitions of the same object, so ODR is not violated.