This is a follow-up to d3e43bbe which resolved the issue for value types, but not for foreign reference types.
This change teaches IRGen that a base type of a C++ type might occupy less memory than its `sizeof`, specifically, it might only use `dsize` amount of memory.
rdar://147527755
In C++, a primary base class that is placed in the beginning of the type's memory layout isn't always the type that is the first in the list of bases – the base types might be laid out in memory in a different order.
This makes sure that IRGen handles base types of C++ structs in the correct order.
This fixes an assertion in asserts-enabled compilers, and an out-of-memory error in asserts-disabled compilers. The issue was happening for both value types and foreign reference types. This change also includes a small refactoring to reuse the logic between the two code paths.
rdar://140848603
A C++ record destructor that is called implicitly in the landing pad cleanup code of a constructor after a field is initialized might only be referenced there, so the Clang decl finder should pick it up when scanning the AST for interesting Decls that might have to be emitted into one LLVM IR module.
This allows calling a C++ function with default arguments from Swift without having to explicitly specify the values of all arguments.
rdar://103975014
Even if a virtual method is not used directly from Swift, it might get emitted into the vtable, and in that case the IR for it should be emitted to avoid linker errors.
Fixes https://github.com/apple/swift/issues/61730.
Previously we tried to instantiate templates in unevaluated contexts. Some of these templates might not be instantiatable, which caused compile errors, while the equivalent C++ code compiles and runs with no issue.
This was problematic for `std::vector` with libstdc++ on Linux.
Fixes https://github.com/apple/swift/issues/61547.
If a templated C++ class is used from two different C++ modules, and those modules are included in Swift, Clang will create different two different redecls for the class & its methods.
For each of the methods, only one of the redecls would actually have a body, the other would have empty bodies. That prevents `ClangDeclFinder` from properly finding the symbols referenced from a method body, leading to a linker error in some cases, when the first redecl is missing a body.
This prevents `std::string` from being used on Linux:
```
/tmp/use-std-string-2dd593.o:use-std-string-2dd593.o:function void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag): error: undefined reference to 'bool __gnu_cxx::__is_null_pointer<char>(char*)'
/tmp/use-std-string-2dd593.o:use-std-string-2dd593.o:function void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag): error: undefined reference to 'std::iterator_traits<char*>::difference_type std::distance<char*>(char*, char*)'
clang-13: error: linker command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)
```
This addresses SR-15272.
When you have a function (e.g. 'foo') which is used in a constructor
initializer (e.g. constructor of some class 'Bar'), and you use the
constructor from swift code without directly using the function (e.g.
Bar's ctor is used from swift but foo isn't, foo is used from Bar's ctor),
you will get a link error. My fix is as follows:
When walking the clangAST to be imported, make sure you look at each
CXXCtorInitializer for each CXXConstructorDecl you see.
Adds tests for using std-vector and some other interesting types.
This patch fixes four mis conceptions that the compiler was previously making:
1. Implicit destructors have no side effects. (Yes, this means we were not cleaning up some objects.)
2. Implicit destructors have bodies. (Technically they do, but the body doesn't include CallExprs that they make when lowered to IR.)
3. Functions other than methods can be uninstantiated templates.
4. Uninstantiated templates may have executable code. (I.e., we can never take the fast path.)
And makes sure that we visit the destructor of any VarDecl (including parameters).
Lazily instantiate class template members. This means we no longer
reject some programs that clang accepts, such as the following:
```
template<class T> struct Foo { void fail(T value) { value.fail(); } };
using Bar = Foo<int>;
```
The above program will not error so long as `Bar::fail` isn't called.
(Previously, we'd fail to import `Bar`.)
clang::DeclContext::decls_begin() deserializes all the pre-compiled headers
imported into the current translation unit, which is expensive.
Workaround this by disabling the emission of PragmaCommentDecls unless we're
building for a Windows target, or LTO is enabled.
A better fix would be to serialize a separate index for PragmaCommentDecls
so that they can be deserialized without deserializing everything else.
I filed rdar://problem/74036099 to track the longer-term fix.
Fixes rdar://problem/73951264.
Currently the following code doesn't work when `callConstructor()` is called from Swift:
```cc
inline int increment(int value) {
return value + 1;
}
struct Incrementor {
int incrementee;
Incrementor(int value) : incrementee(increment(value)) {}
}
int callConstructor(int value) {
return Incrementor(value).incrementee;
}
```
The issue is that we don't generate `IR` for the `increment()` function when it's only called from a constructor or a method.
Swift is aware of the existence of `increment()` and we see it in `IR` as `declare incrementEi`, however, as we don't to emit a definition, we get the following error:
```
Incrementor::Incrementor(int): error: undefined reference to 'increment(int)'
```
This PR fixes this by visiting constructors and methods in `IRGen` and calling `HandleTopLevelDecl()` with all used declarations, which results in emitting definitions for the used declarations.
Co-authored-by: Marcel Hlopko <hlopko@google.com>
emitClangDecl interacts with clang and LLVM to achieve C interop. On the
LLVM side, CodeGenModule::EmitGlobal asserts if the decl eventually
passed to it is not a "file scoped" via VarDecl::isFileVarDecl.
LLVM currently asserts on local extern variables in C headers passed to
Swift when the definition exists outside that header. To fix this, we
need to ensure that we are only passing Decls that do not trip the
assertion but not unduly limit local extern variables when the
corresponding definition exists inside that header.
We can do that fairly simply by checking for isFileVarDecl just before
we hand-off to clang. When the definition for the local extern variable
exists inside the header, isFileVarDecl is true, and if it exists
elsewhere, it is false. This matches up with the assert expectation on
the LLVM side exactly.
This indirectly addresses #28968, since that contains the only part of
the Swift stdlib that uses a local extern variable, but any header that
is used with Swift that contains a local extern variable will cause the
compiler to assert when built with assertions enabled.
This is important, for example, for linking correctly to the C++
standard library on Windows, which uses `#pragma comment(lib, ...)` in
its headers to specify the correct library to link against.
Previously, we were only doing this after the fast-path code that
handles decls without any executable code. This meant, however, that we
were potentially processing these decls multiple times. This is
definitely inefficient; it may even be a correctness issue, depending on
what amount of checking `HandleTopLevelDecl` does to see if it has
processed a particular decl before (which I'm not sure about either
way).
Adds a test that fails without the fix.
The fix consists simply of removing a return statement; as a result, we
now always emit code for functions referenced from the function we are
currently emitting.
Previously, this was not done for externally visible functions. This
goes all the way back to when `GenClangDecl.cpp` was originally introduced here:
ee22004b84
I speculate that the reason for doing this was that in C and Objective-C, we
can assume that an externally visible function will be provided by some
`.o` file we're linking against (though I'm not sure if this is in fact
true for C99 inline functions). At any rate, this assumption is no longer true
for C++ inline functions.
Previously, we had hacks in place to eagerly emit everything in
the global ExternalDefinitions list. These can now be removed,
at least at the IRGen layer.
We need this because that global state includes tables like llvm[.compiler].used
which would otherwise be sorely missed.
This fixes an issue of the clang importer that would cause us to fail whenever
we imported a function (say it is marked as static inline) that performs an
objective-c method call and we optimize the code. The optimizer would not see
the objective-c selector global variable (which is marked private) as being
"used by unkown i.e the objc runtime" and would rightly assume it could
propagate the value of the global variable's initializer value as a constant to
loads of the global variable.
Now we call the ClangCodeGenerators translation unit finalization code which
will emit these tables and other module flags. We need to take care that we
merge those datastrutures with datastructures that we emit from swift's IRGen.
rdar://21115194
Swift SVN r29176
Per the previous commit we are no longer using this. Minor save in
simplicity and maybe a bit of compilation time as well.
In the long run IRGen probably shouldn't be pulling information from the
AST at all; the SILModule should be able to tell it what types it needs
to emit information for. But this is still an improvement for now.
No functionality change (that was the previous commit).
Swift SVN r24840
This handles things like NSSwapHostLongLongToBig and MKMapRectMake that
are static inline functions that themselves call other static inline
functions.
<rdar://problem/17227237>
Swift SVN r21080