Skip to content

[C++20] [Modules] <ranges> cannot be included in more than one module #61317

Closed
@camio

Description

@camio
Contributor
// A.cppm
module;
#include <ranges>
export module A;
// B.cppm
module;
#include <ranges>
export module B;
import A;
clang++ -fprebuilt-module-path=. -std=c++20  --precompile A.cppm -o A.pcm
clang++ -fprebuilt-module-path=. -std=c++20  --precompile B.cppm -o B.pcm

Compilation of the second file results in several errors like this

In module 'A' imported from B.cppm:6:
/usr/sbin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.1/../../../../include/c++/12.2.1/ranges:1258:2: error: 'std::ranges::views::_All::operator()' from module 'A.<global>' is not present in definition of 'std::ranges::views::_All' provided earlier
        operator() [[nodiscard]] (_Range&& __r) const
        ^
/usr/sbin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.1/../../../../include/c++/12.2.1/ranges:1258:2: note: declaration of 'operator()' does not match
        operator() [[nodiscard]] (_Range&& __r) const
        ^

This is using Clang trunk and libstdc++ that is distributed with GCC 12.2.1.

Activity

llvmbot

llvmbot commented on Mar 10, 2023

@llvmbot
Member

@llvm/issue-subscribers-clang-modules

ChuanqiXu9

ChuanqiXu9 commented on Mar 10, 2023

@ChuanqiXu9
Member

Thanks for reporting this! Would you like to reduce the defect report? It will be pretty helpful.

We can reduce the defect report by:

  1. preprocess <ranges> to a local header my_ranges.
  2. include my_ranges in the reproducer.
  3. Remove unnecessary things in my_ranges until we can't make it any more.
camio

camio commented on Mar 11, 2023

@camio
ContributorAuthor

This reduced version reproduces the issue.

// A.cppm
module;
#include "foo.h"
export module A;
// B.cppm
module;
#include "foo.h"
export module B;
import A;
// foo.h
#ifndef _FOO
#define _FOO

template <typename T> struct Foo {
  Foo(T) {}
};

template <typename T> Foo(T &) -> Foo<T>;

struct Bar {
  template <typename T>
    requires requires { Foo{T()}; }
  void baz() const {}
};

#endif

The issue seems to be related to the deduction guide. If the requires clause is changed to Foo<T>{T()};, the issue appears to go away.

davidstone

davidstone commented on Mar 11, 2023

@davidstone
Contributor

This feels a lot like #60486. Note in particular "The practical effect of this bug is that #include <ranges> fails when used in two modules with libstdc++."

self-assigned this
on Mar 14, 2023
camio

camio commented on Mar 14, 2023

@camio
ContributorAuthor

Thank you!

mizvekov

mizvekov commented on Jun 12, 2024

@mizvekov
Contributor

I have come across this change while working on another problem.

The fix which was committed is not correct : The profile function is supposed to support structural comparison, not referential comparison. It's even inconsistent that it would arbitrarily pick referential comparisons for 'TemplateDecl' names, but pick structural for everything else.

This can't be the real solution: When we build canonical types, we start with canonical components, and profiling these still does the right thing, because for canonical stuff, structural and referential comparisons are equivalent.

This fix causes issues where TemplateNames would become canonicalized on the first spelling appearing in source, and their spellings in diagnostics becoming inconsistent.

For example, some libcxx tests emitting diagnostics with different spellings depending on whether they were built with modules or not.

8 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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

      Participants

      @mizvekov@davidstone@camio@EugeneZelenko@llvmbot

      Issue actions

        [C++20] [Modules] <ranges> cannot be included in more than one module · Issue #61317 · llvm/llvm-project