Skip to content

[modules] Compilation success depends on order of declarations in the modulemap #131814

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ldionne opened this issue Mar 18, 2025 · 2 comments
Open
Labels
clang:modules C++20 modules and Clang Header Modules

Comments

@ldionne
Copy link
Member

ldionne commented Mar 18, 2025

Consider the following set of headers:

// myvector.h
#ifndef MYVECTOR_H
#define MYVECTOR_H

#include <bit_ref.h>

template <class _Allocator>
struct MyVector {
  typedef bool value_type;
  typedef unsigned long __storage_type;
  friend class MyBitIterator<MyVector, false>;
};

#endif
// bit_ref.h
#ifndef BIT_REF_H
#define BIT_REF_H

#include <bit_ref_fwd.h>

#endif
// bit_ref_fwd.h
#ifndef BIT_REF_FWD_H
#define BIT_REF_FWD_H

template <class _Cp, bool _IsConst, typename _Cp::__storage_type = 0>
class MyBitIterator {};

#endif

And the following modulemap:

module mystd {
  module myvector {
    header "myvector.h"
    export mystd.bit_ref
  }

  module bit_ref_fwd {
    header "bit_ref_fwd.h"
  }
  module bit_ref {
    header "bit_ref.h"
    export mystd.bit_ref_fwd
  }
}

The following fails to compile:

echo '#include <myvector.h>' | clang++ -x c++ - -std=c++17 -fmodules -fcxx-modules -Xclang -fmodules-local-submodule-visibility -fsyntax-only -I $(dirname ${0}) -fmodules-cache-path="$(mktemp -d)"

The error is:

While building module 'mystd' imported from <stdin>:1:
In file included from <module-includes>:1:
./repro-modules/myvector.h:11:16: error: missing '#include "bit_ref_fwd.h"'; 'MyBitIterator' must be declared before it is used
   11 |   friend class MyBitIterator<MyVector, false>;
      |                ^
./repro-modules/bit_ref_fwd.h:5:7: note: declaration here is not visible
    5 | class MyBitIterator {};
      |       ^
<stdin>:1:10: fatal error: could not build module 'mystd'
    1 | #include <myvector.h>
      |  ~~~~~~~~^
2 errors generated.

A few things can be observed:

  1. If we move the definition of bit_ref_fwd and bit_ref before the definition of myvector in the modulemap, the issue goes away.
  2. If we remove export mystd.bit_ref from the myvector module, the issue goes away.
  3. If we add a direct include of #include <bit_ref_fwd.h> in myvector.h, the issue goes away.

Is this behavior intended? If the order of module definitions in a modulemap matters, there should be a warning that tells us when the compiler encounters something that has not been defined yet in the modulemap. If the order is irrelevant, then there's a bug in Clang.

This was discovered while investigating #127015.

@ldionne ldionne added clang Clang issues not falling into any other category clang:modules C++20 modules and Clang Header Modules labels Mar 18, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 18, 2025

@llvm/issue-subscribers-clang-modules

Author: Louis Dionne (ldionne)

Consider the following set of headers:
// myvector.h
#ifndef MYVECTOR_H
#define MYVECTOR_H

#include &lt;bit_ref.h&gt;

template &lt;class _Allocator&gt;
struct MyVector {
  typedef bool value_type;
  typedef unsigned long __storage_type;
  friend class MyBitIterator&lt;MyVector, false&gt;;
};

#endif
// bit_ref.h
#ifndef BIT_REF_H
#define BIT_REF_H

#include &lt;bit_ref_fwd.h&gt;

#endif
// bit_ref_fwd.h
#ifndef BIT_REF_FWD_H
#define BIT_REF_FWD_H

template &lt;class _Cp, bool _IsConst, typename _Cp::__storage_type = 0&gt;
class MyBitIterator {};

#endif

And the following modulemap:

module mystd {
  module myvector {
    header "myvector.h"
    export mystd.bit_ref
  }

  module bit_ref_fwd {
    header "bit_ref_fwd.h"
  }
  module bit_ref {
    header "bit_ref.h"
    export mystd.bit_ref_fwd
  }
}

The following fails to compile:

echo '#include &lt;myvector.h&gt;' | clang++ -x c++ - -std=c++17 -fmodules -fcxx-modules -Xclang -fmodules-local-submodule-visibility -fsyntax-only -I $(dirname ${0}) -fmodules-cache-path="$(mktemp -d)"

The error is:

While building module 'mystd' imported from &lt;stdin&gt;:1:
In file included from &lt;module-includes&gt;:1:
./repro-modules/myvector.h:11:16: error: missing '#include "bit_ref_fwd.h"'; 'MyBitIterator' must be declared before it is used
   11 |   friend class MyBitIterator&lt;MyVector, false&gt;;
      |                ^
./repro-modules/bit_ref_fwd.h:5:7: note: declaration here is not visible
    5 | class MyBitIterator {};
      |       ^
&lt;stdin&gt;:1:10: fatal error: could not build module 'mystd'
    1 | #include &lt;myvector.h&gt;
      |  ~~~~~~~~^
2 errors generated.

A few things can be observed:

  1. If we move the definition of bit_ref_fwd and bit_ref before the definition of myvector in the modulemap, the issue goes away.
  2. If we remove export mystd.bit_ref from the myvector module, the issue goes away.
  3. If we add a direct include of #include &lt;bit_ref_fwd.h&gt; in myvector.h, the issue goes away.

Is this behavior intended? If the order of module definitions in a modulemap matters, there should be a warning that tells us when the compiler encounters something that has not been defined yet in the modulemap. If the order is irrelevant, then there's a bug in Clang.

This was discovered while investigating #127015.

@ldionne
Copy link
Member Author

ldionne commented Mar 18, 2025

Attaching a full reproducer.

repro-modules.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:modules C++20 modules and Clang Header Modules
Projects
None yet
Development

No branches or pull requests

3 participants