skip to Main Content

I have following program:

#include <cstdio>

import animal;

int main() {
 auto s = makeSound();
 printf("%s", s.c_str());
 return 0;
}

and module interface:

module;
#include <string>
export module animal;
import :sound;

export std::string makeSound() {
 return makeSound_Impl();
}

and module implementation unit:

module;

#include <string>

module animal:sound;

std::string makeSound_Impl() {
 return "Wroooarrh";
}

Program is compiled with:

g++ -fmodules-ts -g -std=c++20 animal_sound.cpp -c -o animal_sound.o
g++ -fmodules-ts -g -std=c++20 animal.cpp -c -o animal.o
g++ -fmodules-ts -g -std=c++20 animal.o animal_sound.o main.cpp -o main.exe

Compiler version:

g++ --version
g++ (Ubuntu 13.1.0-8ubuntu1~22.04) 13.1

Program crashes on basic_string:

Program received signal SIGSEGV, Segmentation fault.
0x00005555555566c2 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_data (this=0xd00aa32b9e55bf00) at /usr/include/c++/13/bits/basic_string.h:223
223           { return _M_dataplus._M_p; }
(gdb) bt
#0  0x00005555555566c2 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_data (this=0x0) at /usr/include/c++/13/bits/basic_string.h:223
#1  0x0000555555556f3a in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::c_str (this=0x7fffffffda50) at /usr/include/c++/13/bits/basic_string.h:2584
#2  0x0000555555556ea6 in main () at main.cpp:7

When compiled with module ‘animal’ defining makeSound directly (not working as proxy to implementation unit):

module;
#include <string>
export module animal;

export std::string makeSound() {
 return "Sound!";
}

Everything works fine (program does not crash). Am I doing something wrong, or that’s a compiler issue?

EDIT

Interestingly I was able to reproduce the issue without implementation units. If no include <string> is present in module ‘animal’ then problem is gone.

module;
#include <string>
export module animal:sound;

export std::string makeSound() {
 return "Wroooarrh";
}
module;
// #include <string>  // Adding include makes program crash
export module animal;
export import :sound;

EDI2

Reported bug on GCC Bugzilla: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111447

2

Answers


  1. Two ways to make this work

    I found two ways to make this work.

    1. Change module animal:sound from an implementation unit into an interface unit.
    2. Eliminate module partition animal:sound, and add an implementation unit for module animal.

    These solutions were tests using MSVC.

    Method 1

    This was the simpler of the two methods.

    I merely added the keyword export to the module declaration for module animal:sound.

    // animal-sound.ixx
    module;
    
    #include <string>
    
    export module animal:sound;  // add the keyword `export`
    
    std::string makeSound_Impl() {
        return "Wroooarrh";
    }
    

    Nothing else was changed, and the program ran fine.

    I am still unsure what to make of Microsoft’s explanation that, "A partition has an interface file, and zero or more implementation files." (See Module partition files.)

    If true, that would explain the problems cited in the OP. The program there has an implementation unit for the partition animal:sound, but no accompanying interface unit.

    In a cursory reading of the material at CppReference, and an even quicker scan of "Section 10.1 Module units and purviews" in the C++ Standard, I could not confirm the Microsoft statement.

    Method 2

    Another way to make this work is to create a module implementation unit for module animal directly.

    This method eliminates the module partition animal:sounds.

    The main routine is identical to that in the original question.

    // main.cpp
    #include <cstdio>
    
    import animal;
    
    int main() {
        auto s = makeSound();
        printf("%s", s.c_str());
        return 0;
    }
    

    Next comes the module interface unit for module animal.

    // animal.ixx
    // Module Interface Unit
    // (For gcc, this may be named "animal.cpp".)
    module;
    #include <string>
    export module animal;
    
    // Declared, but not exported.
    std::string makeSound_Impl();
    
    export std::string makeSound() {
        return makeSound_Impl();
    }
    

    One of the advantages to using .ixx for interface units is that .cpp is available for implementation units. Hence the name animal.cpp below.

    // animal.cpp
    // Module Implementation Unit
    // (For gcc, this might be named "animal-impl.cpp".)
    module;
    #include <string>
    
    module animal;
    std::string makeSound_Impl() {
        return "Wroooarrh";
    }
    

    The output is as expected:

    Wroooarrh
    
    Login or Signup to reply.
  2. The problem you seem to be having is due to each of the module units in the same module having a #include <string> in them. This should not be a problem; there should be nothing wrong with different module units in the same module including the same header in their global module fragments. But your compiler won’t seem to let you do it.

    That makes it a compiler bug.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search