C++ modules: Multiply defined symbols no longer an error?

If you have two classic translation units which both define the same symbol (let’s say auto fun0() -> void), I get a fatal error LNK1169: one or more multiply defined symbols found in MSVC as it violates the ODR.

One of the first steps I made with C++ modules was trying out the behavior with that basic principle. So we have two module files (module0.ixx and module1.ixx) with this almost identical content:

// module0.ixx
export module module0;
import <cstdio>;
export void f_test() { printf("f_test()\n"); }

// module1.ixx
export module module1;
import <cstdio>;
export void f_test() { printf("f_test()\n"); }

In my main.cpp, I do

import module0;
import module1;
auto main() -> int{
    f_test();
}

To my surprise, this compiles just fine. With that come the expected problems: If the definition is different, the behavior depends on the order etc. Is this expected? This was 5 minutes into playing around with modules and seems pretty baffling.

>Solution :

"Multiply defined symbols no longer an error?" – They were never required to be an error. Violation of the ODR is "ill-formed; no diagnostic required". Which basically means undefined behavior ensues, like you see here.

This issue is not specifically endemic to modules. "Old C++" can exhibit the same behavior.

// oops_header.h
#ifndef OOPS
#error OOPS
#endif

#include <iostream>

inline void oops_func() { std::cout << OOPS; }

And we the same shenanigans when we include it and mess with the macro

// tu1.cpp
#define OOPS 123
#include <oops_header.h>
void a() { oops_func(); }

// tu2.cpp
#define OOPS 42
#include <oops_header.h>
void b() { oops_func(); }

Where a main function like this

extern void a();
extern void b();
int main() {
  a();
  b();
}

Will exhibit the exact same problems you encountered with the modules. The output will depend on the stars, because I violated the ODR (inline functions are required by the ODR to be identical on the token level).

You see it with modules due to an artefact of their implementation today (kinda similar to precompiled headers).

Leave a Reply