Instead of exporting a class or namespace each time a new C++ name
lookup discovers it, track that we have exported the entity on its name
scope, and if a new name lookup finds the same entity, produce the same
clang declaration.
We don't yet populate the bases or fields, so the class types show up as
empty classes in C++ for now. But we do allow calls to static member
functions.
This works by generating two thunks, one in C++ and one in Carbon. For
example, given this input:
```c++
// Carbon:
fn Callme(f: f32) {}
// C++:
void F() {
// This will call `Callme__cpp_thunk`
Carbon::Callme(1.0);
}
```
These functions are generated:
```c++
// Carbon:
fn Callme__carbon_thunk(ref f: f32) {
// Call the target function.
Callme(f);
}
// C++:
// C++ declaration for the Carbon thunk.
void Callme__carbon_thunk(float& f);
void Callme__cpp_thunk(float f) {
// Call the Carbon thunk with args passed by reference.
Callme__carbon_thunk(f);
}
```
For now, all arguments are passed by reference, even if they are simple
types like pointers or i32.
Functions with non-void return types are not supported yet.
Start recording the clang::DeclContext* -> InstId mapping for use in
later operations.
The test update includes removing the initial fail_* test because I
hadn't thought about the use of namespace aliases as a way to test for
the presence of a namespace without the failure caused by not finding
the thing inside the namespace.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Add a clang::ExternalASTSource to begin exposing Carbon entities to
Clang - initially only a single `Carbon` top level namespace.
Subsequent work will add Carbon entities to this namespace.
Likely this CarbonExternalASTSource will be refactored into another
file, tie into/reference SemIR::File and CppFile, etc eventually - but
that'll wait for future patches.
If there's mechanical problems with the current implementation - how I'm
creating the new NamespaceDecl, etc - I'm all ears. It's very much in
the "it seems to work" state, not much more than that.
This does break Clang Modules (header modules, C++20 modules,
precompiled headers, etc) since they're implemented as an
ExternalASTSource as well, and Clang's ASTContext only supports one
ExternalASTSource at a time. To fix that regression we'll need to
implement some kind of ExternalASTSource multiplexing support - either
in Clang or Carbon (unclear which).
This regression of modules support can be observed by the following:
`A.h`
```
inline void f1() { }
```
`module.modulemap`
```
module A {
header "A.h"
export *
}
```
`test.carbon`
```
import Cpp inline '''
// Hardcode the pragma to ensure this isn't silently falling back to
// textual inclusion.
void f2() {
f1();
}
''';
```
```
carbon compile test.carbon -- -I . -fmodules -fimplicit-modules -fmodules-cache-path=module_cache
```
I wrote a `file_test` test for this, but it doesn't /quite/ work because
`file_test` provides an in-memory filesystem for tests to make them more
hermetic, but Clang's Filesystem abstrtaction is for reading only - so
the module that's written out successfully can't be found when it needs
to be read back in - so the test doesn't pass as a baseline. Clang does
have support for `llvm::vfs::OutputBackend` which allows virtualizing
output - which I guess we could tie together with the InMemoryFilesystem
we use for input to make such a test work. But I guess that's not worth
the effort here?
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>