Skip to content

Support C++20 Modules in clang-repl #79261

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

Merged
merged 1 commit into from
Jan 24, 2024

Conversation

ChuanqiXu9
Copy link
Member

This comes from when I playing around clang-repl with moduels : )

I succeeded to import std with https://libcxx.llvm.org/Modules.html and calling std::printf after this patch.

I want to put the documentation part to https://clang.llvm.org/docs/StandardCPlusPlusModules.html in a separate commit.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules labels Jan 24, 2024
@llvmbot
Copy link
Member

llvmbot commented Jan 24, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-modules

Author: Chuanqi Xu (ChuanqiXu9)

Changes

This comes from when I playing around clang-repl with moduels : )

I succeeded to import std with https://libcxx.llvm.org/Modules.html and calling std::printf after this patch.

I want to put the documentation part to https://clang.llvm.org/docs/StandardCPlusPlusModules.html in a separate commit.


Full diff: https://github.com/llvm/llvm-project/pull/79261.diff

4 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/include/clang/Basic/LangOptions.def (+1-1)
  • (modified) clang/lib/Serialization/ASTReaderDecl.cpp (+3-3)
  • (added) clang/test/Interpreter/cxx20-modules.cppm (+31)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fc7511e9136734..db3d74e124e7d1 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -191,6 +191,8 @@ Crash and bug fixes
 Improvements
 ^^^^^^^^^^^^
 
+- Support importing C++20 modules in clang-repl.
+
 Moved checkers
 ^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 8fc75e1cca0399..1e671a7c460163 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -485,7 +485,7 @@ VALUE_LANGOPT(FuchsiaAPILevel, 32, 0, "Fuchsia API level")
 // on large _BitInts.
 BENIGN_VALUE_LANGOPT(MaxBitIntWidth, 32, 128, "Maximum width of a _BitInt")
 
-LANGOPT(IncrementalExtensions, 1, 0, " True if we want to process statements"
+COMPATIBLE_LANGOPT(IncrementalExtensions, 1, 0, " True if we want to process statements"
         "on the global scope, ignore EOF token and continue later on (thus "
         "avoid tearing the Lexer and etc. down). Controlled by "
         "-fincremental-extensions.")
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index a149d82153037f..867f4c47eaeceb 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -3286,10 +3286,10 @@ DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader,
   if (auto *OID = dyn_cast<ObjCInterfaceDecl>(DC))
     return OID->getDefinition();
 
-  // We can see the TU here only if we have no Sema object. In that case,
-  // there's no TU scope to look in, so using the DC alone is sufficient.
+  // We can see the TU here only if we have no Sema object. It is possible
+  // we're in clang-repl so we still need to get the primary context.
   if (auto *TU = dyn_cast<TranslationUnitDecl>(DC))
-    return TU;
+    return TU->getPrimaryContext();
 
   return nullptr;
 }
diff --git a/clang/test/Interpreter/cxx20-modules.cppm b/clang/test/Interpreter/cxx20-modules.cppm
new file mode 100644
index 00000000000000..bc2b722f6b5197
--- /dev/null
+++ b/clang/test/Interpreter/cxx20-modules.cppm
@@ -0,0 +1,31 @@
+// UNSUPPORTED: system-aix
+//
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang -std=c++20 %t/mod.cppm --precompile \
+// RUN:     -o %t/mod.pcm
+// RUN: %clang %t/mod.pcm -c -o %t/mod.o
+// RUN: %clang -shared %t/mod.o -o %t/libmod.so
+//
+// RUN: cat %t/import.cpp | env LD_LIBRARY_PATH=%t:$LD_LIBRARY_PATH \
+// RUN:     clang-repl -Xcc=-std=c++20 -Xcc=-fmodule-file=M=%t/mod.pcm \
+// RUN:     | FileCheck %t/import.cpp
+
+//--- mod.cppm
+export module M;
+export const char* Hello() {
+    return "Hello Interpreter for Modules!";
+}
+
+//--- import.cpp
+
+%lib libmod.so
+
+import M;
+
+extern "C" int printf(const char *, ...);
+printf("%s\n", Hello());
+
+// CHECK: Hello Interpreter for Modules!

Copy link
Contributor

@vgvassilev vgvassilev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm! Thank you @ChuanqiXu9!

@ChuanqiXu9 ChuanqiXu9 merged commit dd3e6c8 into llvm:main Jan 24, 2024
@ChuanqiXu9 ChuanqiXu9 deleted the ModulesInClangRepl branch January 24, 2024 07:45
@dyung
Copy link
Collaborator

dyung commented Jan 24, 2024

Hi @ChuanqiXu9, the test you added is failing on the PS4 bot because for the PS4 target, it requires an external linker which is not present/available. Can the test be rewritten to not require linking?

https://lab.llvm.org/buildbot/#/builders/139/builds/57928

clang: error: unable to execute command: Executable "orbis-ld" doesn't exist!
clang: error: linker command failed with exit code 1 (use -v to see invocation)

@ChuanqiXu9
Copy link
Member Author

ChuanqiXu9 commented Jan 24, 2024

Hi @ChuanqiXu9, the test you added is failing on the PS4 bot because for the PS4 target, it requires an external linker which is not present/available. Can the test be rewritten to not require linking?

https://lab.llvm.org/buildbot/#/builders/139/builds/57928

clang: error: unable to execute command: Executable "orbis-ld" doesn't exist!
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Oh, maybe I need to add more requires to the test.

I tried to handle it in c125965. It shouldn't fail on PS4 any more.

ChuanqiXu9 added a commit that referenced this pull request Jan 24, 2024
The previous test can't work on other platforms like PS4.

Address the comments in
#79261 (comment)
@nathanchance
Copy link
Member

For what it's worth, this test appears to fail when LLVM_DEFAULT_TARGET_TRIPLE is changed (my script sets it to the output of my Linux distribution's clang -print-target-triple)

error: PCH file was compiled for the target 'x86_64-pc-linux-gnu' but the current translation unit is being compiled for target 'x86_64-unknown-linux-gnu'
error: module file .../tools/clang/test/Interpreter/Output/cxx20-modules.cppm.tmp/mod.pcm cannot be loaded due to a configuration mismatch with the current compilation [-Wmodule-file-config-mismatch]
error: Parsing failed.

@ChuanqiXu9
Copy link
Member Author

For what it's worth, this test appears to fail when LLVM_DEFAULT_TARGET_TRIPLE is changed (my script sets it to the output of my Linux distribution's clang -print-target-triple)

error: PCH file was compiled for the target 'x86_64-pc-linux-gnu' but the current translation unit is being compiled for target 'x86_64-unknown-linux-gnu'
error: module file .../tools/clang/test/Interpreter/Output/cxx20-modules.cppm.tmp/mod.pcm cannot be loaded due to a configuration mismatch with the current compilation [-Wmodule-file-config-mismatch]
error: Parsing failed.

Thanks. But I am not sure how should I change the test. Do you have any idea or suggestion?

@vgvassilev
Copy link
Contributor

Perhaps we are not propagating the correct triple down to the module build action?

@ChuanqiXu9
Copy link
Member Author

It looks true but the test does the same thing as other tests to build modules

@nathanchance
Copy link
Member

This is out of my wheelhouse to debug to be honest but it seems to me that clang-repl does not respect LLVM_DEFAULT_TARGET_TRIPLE somehow? This test does the same thing as other tests to build modules but this appears to be the only one that uses clang-repl to consume the .pcm.

@vgvassilev
Copy link
Contributor

We pass the CompilerInstance's notion of the target triple this commit explains it: 49f9532

@nathanchance, can clang-repl be run on your setup? If the Jit is happy about the target triple and we can jit code that'd probably mean that the modules infrastructure gets confused about the target triple and build a C++ module for the wrong configuration.

@nathanchance
Copy link
Member

@vgvassilev Yes, it appears so, I tried one of the examples from the documentation since I have no prior experience with clang-repl.

$ clang-repl --version
LLVM (http://llvm.org/):
  LLVM version 19.0.0git
  Optimized build with assertions.

$ clang-repl
clang-repl> #include <iostream>
clang-repl> int sum(int a, int b){ return a+b; };
clang-repl> int c = sum(9,10);
clang-repl> std::cout << c << std::endl;
19
clang-repl> ^D

@nikic
Copy link
Contributor

nikic commented Jan 29, 2024

Normal clang creates a driver using the default target triple here:

Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);

clang-repl appears to use IncrementalCompilerBuilder, which uses getProcessTriple() here:

driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0],
llvm::sys::getProcessTriple(), Diags);

getProcessTriple() is based on LLVM_HOST_TRIPLE with some fixups.

I'm not really sure what the right fix here is. It makes sense that an interpreter uses the host triple by default, but it's also a problem that clang and clang-repl use different default triples.

@vgvassilev
Copy link
Contributor

vgvassilev commented Jan 29, 2024

@nikic, thanks for the details!

Until this change we sailed fairly well. It seems that the pcm rigorously records the clang notion of the triple which is probably what we want. However, if we are building a pcm in the context of clang-repl would it make sense to use the getProcessTriple notion for that pcm -- that'd be the behavior if we used header files instead of a module.

mysterymath added a commit to llvm-mos/llvm-mos that referenced this pull request Jan 29, 2024
Looks like it doesn't work when the default host triple is changed:
llvm/llvm-project#79261
@nikic
Copy link
Contributor

nikic commented Jan 30, 2024

Until this change we sailed fairly well. It seems that the pcm rigorously records the clang notion of the triple which is probably what we want. However, if we are building a pcm in the context of clang-repl would it make sense to use the getProcessTriple notion for that pcm -- that'd be the behavior if we used header files instead of a module.

The pcm here is being generated by clang, not by clang-repl, so I'm not sure how we would know that we need to switch the triple.

@vgvassilev
Copy link
Contributor

We have a LangOption called IncrementalExtensions. We might be able to use it there.

@ChuanqiXu9
Copy link
Member Author

IncrementalExtensions

But the change itself is to make IncrementalExtensions a compatible lang options. So that we don't need to specify it when generating the modules.

@ChuanqiXu9
Copy link
Member Author

I am wondering if it helps if we specify the target triple in the test, then it won't be so troublesome.

@vgvassilev
Copy link
Contributor

IncrementalExtensions

But the change itself is to make IncrementalExtensions a compatible lang options. So that we don't need to specify it when generating the modules.

I mean conditionally if IncrementalExtensions is set we change the target triple in the clang fork of the C++ module build.

I am wondering if it helps if we specify the target triple in the test, then it won't be so troublesome.

I was wondering that too. Can we express that in lit?

@ChuanqiXu9
Copy link
Member Author

IncrementalExtensions

But the change itself is to make IncrementalExtensions a compatible lang options. So that we don't need to specify it when generating the modules.

I mean conditionally if IncrementalExtensions is set we change the target triple in the clang fork of the C++ module build.

I am not sure if it is possible since we don't know the clang fork before we see the import. Even if we can, it is more or less problematic if there are multiple imported module from different fork.

I am wondering if it helps if we specify the target triple in the test, then it won't be so troublesome.

I was wondering that too. Can we express that in lit?

For %clang_cc1, we can use %clang_cc1 -triple=x86_64-linux-gnu. I am not sure about clang-repl. It may be possible by -Xcc=.

But due to I can't reproduce the failure, @nathanchance would you like to make this? I don't want to make something that I can't test.

@vgvassilev
Copy link
Contributor

IncrementalExtensions

But the change itself is to make IncrementalExtensions a compatible lang options. So that we don't need to specify it when generating the modules.

I mean conditionally if IncrementalExtensions is set we change the target triple in the clang fork of the C++ module build.

I am not sure if it is possible since we don't know the clang fork before we see the import. Even if we can, it is more or less problematic if there are multiple imported module from different fork.

I can find arguments in changing the clang-repl target triple to match the loaded module… That would have some reasoning but maybe we won’t be able to start the jit if the triples are too different.

@nathanchance
Copy link
Member

But due to I can't reproduce the failure, @nathanchance would you like to make this? I don't want to make something that I can't test.

I don't mind submitting something if I have some guidance around how this should be handled (I am a little lost in this thread at the moment). Alternatively, I am able to reproduce this with:

(/usr/bin/clang -print-target-triple is x86_64-pc-linux-gnu, if you'd rather use it directly)

$ cmake \
-B build \
-G Ninja \
-S llvm \
-Wno-dev \
--log-level=NOTICE \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DLLVM_DEFAULT_TARGET_TRIPLE=$(/usr/bin/clang -print-target-triple) \
-DLLVM_ENABLE_PROJECTS=clang \
-DLLVM_USE_LINKER=lld

$ ninja -C build check-clang
...
error: PCH file was compiled for the target 'x86_64-pc-linux-gnu' but the current translation unit is being compiled for target 'x86_64-unknown-linux-gnu'
error: module file .../tools/clang/test/Interpreter/Output/cxx20-modules.cppm.tmp/mod.pcm cannot be loaded due to a configuration mismatch with the current compilation [-Wmodule-file-config-mismatch]
error: Parsing failed.
...

so it should be easy to test and verify the fix.

Copy link
Member Author

@ChuanqiXu9 ChuanqiXu9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I had in mind

Comment on lines +7 to +14
// RUN: %clang -std=c++20 %t/mod.cppm --precompile \
// RUN: -o %t/mod.pcm
// RUN: %clang %t/mod.pcm -c -o %t/mod.o
// RUN: %clang -shared %t/mod.o -o %t/libmod.so
//
// RUN: cat %t/import.cpp | env LD_LIBRARY_PATH=%t:$LD_LIBRARY_PATH \
// RUN: clang-repl -Xcc=-std=c++20 -Xcc=-fmodule-file=M=%t/mod.pcm \
// RUN: | FileCheck %t/import.cpp
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// RUN: %clang -std=c++20 %t/mod.cppm --precompile
// RUN: -o %t/mod.pcm -triple=x86_64-linux-gnu
// RUN: %clang %t/mod.pcm -c -o %t/mod.o -triple=x86_64-linux-gnu
// RUN: %clang -shared %t/mod.o -o %t/libmod.so -triple=x86_64-linux-gnu
//
// RUN: cat %t/import.cpp | env LD_LIBRARY_PATH=%t:$LD_LIBRARY_PATH
// RUN: clang-repl -Xcc=-std=c++20 -Xcc=-fmodule-file=M=%t/mod.pcm
// RUN: -Xcc=-triple=x86_64-linux-gnu | FileCheck %t/import.cpp

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nathanchance this is what I expected to test

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

diff --git a/clang/test/Interpreter/cxx20-modules.cppm b/clang/test/Interpreter/cxx20-modules.cppm
index 2c6eba525519..cd2b04fdc547 100644
--- a/clang/test/Interpreter/cxx20-modules.cppm
+++ b/clang/test/Interpreter/cxx20-modules.cppm
@@ -6,13 +6,13 @@
 // RUN: split-file %s %t
 //
 // RUN: %clang -std=c++20 %t/mod.cppm --precompile \
-// RUN:     -o %t/mod.pcm
-// RUN: %clang %t/mod.pcm -c -o %t/mod.o
-// RUN: %clang -shared %t/mod.o -o %t/libmod.so
+// RUN:     -o %t/mod.pcm --target=x86_64-linux-gnu
+// RUN: %clang %t/mod.pcm -c -o %t/mod.o --target=x86_64-linux-gnu
+// RUN: %clang -shared %t/mod.o -o %t/libmod.so --target=x86_64-linux-gnu
 //
 // RUN: cat %t/import.cpp | env LD_LIBRARY_PATH=%t:$LD_LIBRARY_PATH \
 // RUN:     clang-repl -Xcc=-std=c++20 -Xcc=-fmodule-file=M=%t/mod.pcm \
-// RUN:     | FileCheck %t/import.cpp
+// RUN:     -Xcc=--target=x86_64-linux-gnu | FileCheck %t/import.cpp
 
 //--- mod.cppm
 export module M;

appears to work for me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good, would you like to land it? Or I will do it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can land it, thanks for continuing to chase this!

ChuanqiXu9 added a commit that referenced this pull request Jan 31, 2024
See #79261 for details.

It shows that clang-repl uses a different target triple with clang so that it
may be problematic if the calng-repl reads the generated BMI from clang
in a different target triple.

While the underlying issue is not easy to fix, this patch tries to make
this test green to not bother developers.
@steakhal
Copy link
Contributor

steakhal commented Jul 2, 2024

@vgvassilev It appears that this PR added an entry to the Static Analyzer section, and I'm not sure if that's the right one.
Could you please suggest an alternative section where I should move it?

@vgvassilev
Copy link
Contributor

Do you mean the documentation? If so, yes, that’s probably not the right place. I am on my phone but can you suggest a place where we should move this or just move it? I think that was an oversight.

@steakhal
Copy link
Contributor

steakhal commented Jul 2, 2024

Do you mean the documentation? If so, yes, that’s probably not the right place. I am on my phone but can you suggest a place where we should move this or just move it? I think that was an oversight.

Thanks. There is nothing urgent. I was just preparing a PR for syncing the release notes with what we actually did in CSA, so I realized this.

I wanted to check first if you already have a well established place/section where you would prefer to have this, as I couldn't find one in 3 seconds.
You can move it, or alternatively I can also move it.
It's up to you. :)

(The release branch is supposed to branch off on the 23rd of July)

@vgvassilev
Copy link
Contributor

Oh, understood. Perhaps would be better if you move it. I am currently on vacation for a while…

steakhal added a commit that referenced this pull request Jul 2, 2024
Let's just move these under the
`Non-comprehensive list of changes in this release` section.

Resolves:
- #79261 (comment)
- #65484 (comment)
lravenclaw pushed a commit to lravenclaw/llvm-project that referenced this pull request Jul 3, 2024
Let's just move these under the
`Non-comprehensive list of changes in this release` section.

Resolves:
- llvm#79261 (comment)
- llvm#65484 (comment)
kbluck pushed a commit to kbluck/llvm-project that referenced this pull request Jul 6, 2024
Let's just move these under the
`Non-comprehensive list of changes in this release` section.

Resolves:
- llvm#79261 (comment)
- llvm#65484 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants