Modules TS: various problems

I am trying to use the Modules TS implementation in Clang 5.0.0-svn305177.
My module interface file:

#include <string>

export module hello;

export namespace hello
{
  void say (const std::string& name);
}

Module implementation file:

#include <string>
#include <iostream>

module hello;

using namespace std;

namespace hello
{
  void
  say (const string& n)
  {
    cout << "Hello, " << n << '!' << endl;
  }
}

The problems:

1. It seems the .pcm file compiled from the interface file references
   said interface file. If I remove it after generating .pcm, then I get
   an error like this when compiling the implementation file:

   clang++-5.0 -std=c++1z -D__cpp_modules=201704 -fmodules-ts -fmodule-file=hello.a.pcm -o hello.a.o -c -x c++ hello.a.o.ii
   fatal error: malformed or corrupted AST file: 'could not find file '/home/boris/work/build2/hello/m/libmhello/libhello/hello.a.pcm.ii' referenced by AST file 'hello.a.pcm''

   The .pcm is produced with this command line:

   clang++-5.0 -std=c++1z -D__cpp_modules=201704 -fmodules-ts -o hello.a.pcm --precompile -Xclang -fmodules-codegen -Xclang -fmodules-debuginfo -x c++-module hello.a.pcm.ii

2. If I keep the source file, then I get errors along these lines (again,
   when compiling the implementation file):

   In file included from hello.cxx:3:
   In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/string:39:
   /usr/bin/../lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/bits/stringfwd.h:69:48: error: template parameter redefines default argument
     template<typename _CharT, typename _Traits = char_traits<_CharT>,
   /usr/bin/../lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/bits/stringfwd.h:69:48: note: previous default template argument defined here
     template<typename _CharT, typename _Traits = char_traits<_CharT>,

   The same code compiles fine with VC 15u3.

   If I get rid of the <string> inclusion from the interface file (and
   use const char* to pass the name), everything compiles fine.

Thanks,
Boris

I am trying to use the Modules TS implementation in Clang 5.0.0-svn305177.
My module interface file:

#include

export module hello;

export namespace hello
{
void say (const std::string& name);
}

Module implementation file:

#include
#include

module hello;

using namespace std;

namespace hello
{
void
say (const string& n)
{
cout << "Hello, " << n << ‘!’ << endl;
}
}

The problems:

  1. It seems the .pcm file compiled from the interface file references
    said interface file. If I remove it after generating .pcm, then I get
    an error like this when compiling the implementation file:

clang+±5.0 -std=c++1z -D__cpp_modules=201704 -fmodules-ts -fmodule-file=hello.a.pcm -o hello.a.o -c -x c++ hello.a.o.ii
fatal error: malformed or corrupted AST file: ‘could not find file ‘/home/boris/work/build2/hello/m/libmhello/libhello/hello.a.pcm.ii’ referenced by AST file ‘hello.a.pcm’’

The .pcm is produced with this command line:

clang+±5.0 -std=c++1z -D__cpp_modules=201704 -fmodules-ts -o hello.a.pcm --precompile -Xclang -fmodules-codegen -Xclang -fmodules-debuginfo -x c+±module hello.a.pcm.ii

This should be able to be addressed by using -Xclang -fmodules-embed-all-files (see https://reviews.llvm.org/rL253950 for some more info).

Perhaps Richard’ll have ideas on the rest.

I am trying to use the Modules TS implementation in Clang 5.0.0-svn305177.
My module interface file:

#include <string>

export module hello;

export namespace hello
{
  void say (const std::string& name);
}

Module implementation file:

#include <string>
#include <iostream>

module hello;

using namespace std;

namespace hello
{
  void
  say (const string& n)
  {
    cout << "Hello, " << n << '!' << endl;
  }
}

The problems:

1. It seems the .pcm file compiled from the interface file references
   said interface file. If I remove it after generating .pcm, then I get
   an error like this when compiling the implementation file:

   clang++-5.0 -std=c++1z -D__cpp_modules=201704 -fmodules-ts
-fmodule-file=hello.a.pcm -o hello.a.o -c -x c++ hello.a.o.ii
   fatal error: malformed or corrupted AST file: 'could not find file
'/home/boris/work/build2/hello/m/libmhello/libhello/hello.a.pcm.ii'
referenced by AST file 'hello.a.pcm''

   The .pcm is produced with this command line:

   clang++-5.0 -std=c++1z -D__cpp_modules=201704 -fmodules-ts -o
hello.a.pcm --precompile -Xclang -fmodules-codegen -Xclang
-fmodules-debuginfo -x c++-module hello.a.pcm.ii

.pcm files are not a distribution format. You still need the module
interface to be available at the point of use (Clang will use them to emit
text snippets in diagnostics, as well as for some internal purposes where
we avoid making copies of data that's present in a source file). As David
notes, you can use -fmodules-embed-all-files to cause the input files to be
embedded in the .pcm file.

2. If I keep the source file, then I get errors along these lines (again,

   when compiling the implementation file):

   In file included from hello.cxx:3:

This line number doesn't match the above code.

   In file included from /usr/bin/../lib/gcc/x86_64-
linux-gnu/6.2.0/../../../../include/c++/6.2.0/string:39:
   /usr/bin/../lib/gcc/x86_64-linux-gnu/6.2.0/../../../../
include/c++/6.2.0/bits/stringfwd.h:69:48: error: template parameter
redefines default argument
     template<typename _CharT, typename _Traits = char_traits<_CharT>,
   /usr/bin/../lib/gcc/x86_64-linux-gnu/6.2.0/../../../../
include/c++/6.2.0/bits/stringfwd.h:69:48: note: previous default template
argument defined here
     template<typename _CharT, typename _Traits = char_traits<_CharT>,

   The same code compiles fine with VC 15u3.

   If I get rid of the <string> inclusion from the interface file (and
   use const char* to pass the name), everything compiles fine.

I'm not surprised. Clang does not claim to fully implement the Modules TS
yet; the implementation is incomplete. In particular, there is no support
for the semantics of export declarations -- instead, we export everything
declared within the module interface unit. As a result, you're importing
the contents of <string> but not its include guards, so you will see
redefinition errors for all definitions in that header.

If you want to experiment with Modules TS code using the standard library
anyway, the easiest way to get the above code working would be to use a
standard library implementation that provides a module map (for instance,
build with -stdlib=libc++ -fmodules).

Richard Smith <richard@metafoo.co.uk> writes:

.pcm files are not a distribution format. You still need the module
interface to be available at the point of use (Clang will use them to emit
text snippets in diagnostics, as well as for some internal purposes where
we avoid making copies of data that's present in a source file).

My source file is partially preprocessed (-frewrite-includes) and is
transient. More generally, this won't play nice with distributed
compilation or being able to move build directories around.

David Blaikie <dblaikie@gmail.com> writes:

This should be able to be addressed by using -Xclang
-fmodules-embed-all-files [...]

Yes, this works, thanks.

Richard Smith <richard@metafoo.co.uk> writes:

This line number doesn't match the above code.

Yes, my bad, I've killed a couple of irrelevant lines. It was the line
with '#include <string>'.

I'm not surprised. Clang does not claim to fully implement the Modules TS
yet; the implementation is incomplete. In particular, there is no support
for the semantics of export declarations -- instead, we export everything
declared within the module interface unit. As a result, you're importing
the contents of <string> but not its include guards, so you will see
redefinition errors for all definitions in that header.

If you want to experiment with Modules TS code using the standard library
anyway, the easiest way to get the above code working would be to use a
standard library implementation that provides a module map (for instance,
build with -stdlib=libc++ -fmodules).

Let me see if I understand how this will work: if I build libc++ modules,
then '#include <string>' directives will be treated by Clang as module
imports and this will prevent the imported std::string declarations from
being all-exported from my module?

Also, from your previous replies I pieced together that one can use the
import declaration to import "header modules". So, theoretically, I
should be able to replace my '#include <string>' with something like
'import std.core' provided I build an appropriate .pcm?

Thanks,
Boris

Boris Kolpackov <boris@codesynthesis.com> writes:

So, theoretically, I should be able to replace my '#include <string>'
with something like 'import std.core' provided I build an appropriate
.pcm?

Actually, nothing prevents me from defining my own modules-ts std.core
module, even if I am using libstdc++:

// file: std-core.mxx -*- C++ -*-
export module std.core;

#include <string>
#include <iostream> // For compatibility with VC.

I was then able to replace '#include <string>' with 'import std.core'
and everything works except for one little niggle: for some reason
Clang insists that I import in the module's purview:

// file: hello.mxx -*- C++ -*-
export module hello;

import std.core;

export namespace hello
{
  void
  say (const std::string& name);
}

If I move import before the exporting module declaration:

// file: hello.mxx -*- C++ -*-
import std.core;

export module hello;

export namespace hello
{
  void
  say (const std::string& name); // line 9
}

Then I get this error:

hello.mxx:9:14: error: declaration of 'std' must be imported from module 'std.core' before it is required say (const std::string& name);
/usr/bin/../lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/iostream:42:11: note: previous declaration is here namespace std _GLIBCXX_VISIBILITY(default)

VC is happy with either placement and my reading of the spec suggests
that it shouldn't matter (unlike #include). Or am I missing something
here?

Thanks,
Boris

This is another "implementation not finished yet" issue. What's happening
here is that "export module hello;" enters a new module scope, and that new
module scope does not (yet) inherit the set of imported modules from the
global module scope.