c++

Why are friend function definitions are not exported?


Suppose I have a setup like so (Godbolt link):

// header.h
#pragma once

int g(int val);
// main.cpp
#include "header.h"

int main() {
    return g(1);
}
// g.cpp
#include "header.h"

class C {
    /*[[gnu::used]]*/ friend int g(int val) {
        return val;
    }
};

If I compile g.cpp to g.o, and main.cpp to main.o, and try to link them, I get the following linker error:

main.cpp:5:(.text+0xa): undefined reference to `g(int)'

Adding the [[gnu::used]] attribute to the definition of g in g.cpp fixes the issue.

So what seems to be happening is that GCC (and clang exhibits the same behavior) does not realize that the definition of g in g.cpp is used, and so it does not include it in g.o, unless we explicitly tell it to with [[gnu::used]]. (But if we had simply written g as a regular function definition in g.cpp, and not a friend, the compiler would include it in g.o and there would be no linker error.)

My question is essentially how does the compiler (I'm mainly interested in GCC and clang) determine which function definitions need to be included in the object file? Is there something in the standard affecting whether such a friend definition is considered accessible that causes this, or is it simply an implementation detail?


Solution

  • g is implicitly inline as inside class definition. And you will have identical behavior without the friendship Demo

    According to One Definition Rule (ODR)

    For an inline function or inline variable(since C++17), a definition is required in every translation unit where it is odr-used .

    And it is not the case in main.