Skip to content

[C++20] [Modules] False Positive ODR violation diagnostic due to using inconsistent qualified but the same type #78850

Open
@ashley-hawkins

Description

@ashley-hawkins

Clang versions I tested with, from https://apt.llvm.org/ (taken from --version):

  • Debian clang version 18.0.0 (++20240119100743+cd05ade13a66-1~exp1~20240119220916.1830) cd05ade
  • Debian clang version 17.0.6 (5)

Current clang version on compiler explorer: clang version 18.0.0git (https://github.com/llvm/llvm-project.git 4684507)

I'm still not sure whether this is a problem with libstdc++ or a problem with clang so I apologise if this is the wrong place to report, but I get this error when including just <chrono> in one module partition and <memory> in another, here is an example on Compiler Explorer: https://godbolt.org/z/Wvv1h5aYa

module.cc
module;
#include <chrono>
export module repro;
export import :part;
part.cc
module;
#include <memory>
export module repro:part;

In this example I am getting the error 'std::align' has different definitions in different modules

full compiler output
In module 'repro:part' imported from /app/module.cc:4:
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.1/../../../../include/c++/14.0.1/bits/align.h:61:1: error: 'std::align' has different definitions in different modules; definition in module 'repro:part.<global>' first difference is function body
   60 | inline void*
      | ~~~~~~~~~~~~
   61 | align(size_t __align, size_t __size, void*& __ptr, size_t& __space) noexcept
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   62 | {
      | ~
   63 |   if (__space < __size)
      |   ~~~~~~~~~~~~~~~~~~~~~
   64 |     return nullptr;
      |     ~~~~~~~~~~~~~~~
   65 |   const auto __intptr = reinterpret_cast<uintptr_t>(__ptr);
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   66 |   const auto __aligned = (__intptr - 1u + __align) & -__align;
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   67 |   const auto __diff = __aligned - __intptr;
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   68 |   if (__diff > (__space - __size))
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   69 |     return nullptr;
      |     ~~~~~~~~~~~~~~~
   70 |   else
      |   ~~~~
   71 |     {
      |     ~
   72 |       __space -= __diff;
      |       ~~~~~~~~~~~~~~~~~~
   73 |       return __ptr = reinterpret_cast<void*>(__aligned);
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   74 |     }
      |     ~
   75 | }
      | ~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.1/../../../../include/c++/14.0.1/bits/align.h:61:1: note: but in '' found a different body
   60 | inline void*
      | ~~~~~~~~~~~~
   61 | align(size_t __align, size_t __size, void*& __ptr, size_t& __space) noexcept
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   62 | {
      | ~
   63 |   if (__space < __size)
      |   ~~~~~~~~~~~~~~~~~~~~~
   64 |     return nullptr;
      |     ~~~~~~~~~~~~~~~
   65 |   const auto __intptr = reinterpret_cast<uintptr_t>(__ptr);
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   66 |   const auto __aligned = (__intptr - 1u + __align) & -__align;
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   67 |   const auto __diff = __aligned - __intptr;
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   68 |   if (__diff > (__space - __size))
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   69 |     return nullptr;
      |     ~~~~~~~~~~~~~~~
   70 |   else
      |   ~~~~
   71 |     {
      |     ~
   72 |       __space -= __diff;
      |       ~~~~~~~~~~~~~~~~~~
   73 |       return __ptr = reinterpret_cast<void*>(__aligned);
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   74 |     }
      |     ~
   75 | }
      | ~
1 error generated.

I looked at the preprocessed source and saw that the problem causing the function definitions to be considered different was one of them was getting uintptr_t from the global namespace, the other was getting uintptr_t from a using in the std namespace.

I could reproduce the same situation without those included headers to demonstrate the problem:

module.cc
module;
typedef long T;
namespace ns {
    using ::T;
}
namespace ns {
inline void fun() {
    (void)(T)0;
}
}
export module repro;
export import :part;
part.cc
module;
typedef long T;
namespace ns {
inline void fun() {
    (void)(T)0;
}
}
export module repro:part;
CMakeLists.txt
cmake_minimum_required(VERSION 3.28)
project(repro)

set(CMAKE_CXX_STANDARD 20)

add_library(repro)
target_sources(repro PUBLIC FILE_SET CXX_MODULES FILES module.cc part.cc)

And here is the above on compiler explorer: https://godbolt.org/z/Ke6eoGnan and the compiler output from that compiler explorer example:

full compiler output
In file included from /app/module.cc:12:
part.cc:4:13: error: 'ns::fun' has different definitions in different modules; definition in module 'repro:part.<global>' first difference is function body
    4 | inline void fun() {
      | ~~~~~~~~~~~~^~~~~~~
    5 |     (void)(T)0;
      |     ~~~~~~~~~~~
    6 | }
      | ~
module.cc:7:13: note: but in '' found a different body
    7 | inline void fun() {
      | ~~~~~~~~~~~~^~~~~~~
    8 |     (void)(T)0;
      |     ~~~~~~~~~~~
    9 | }
      | ~
1 error generated.

Metadata

Metadata

Assignees

Labels

clang:modulesC++20 modules and Clang Header Modules

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions