Skip to content

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

Open
@ldionne

Description

@ldionne
Member

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.

Activity

added
clangClang issues not falling into any other category
clang:modulesC++20 modules and Clang Header Modules
on Mar 18, 2025
llvmbot

llvmbot commented on Mar 18, 2025

@llvmbot
Member

@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

ldionne commented on Mar 18, 2025

@ldionne
MemberAuthor

Attaching a full reproducer.

repro-modules.zip

removed
clangClang issues not falling into any other category
on Mar 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    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

        Participants

        @ldionne@EugeneZelenko@llvmbot

        Issue actions

          [modules] Compilation success depends on order of declarations in the modulemap · Issue #131814 · llvm/llvm-project