Attach the cleanup to the `Temporary` instruction instead of to the
`TemporaryStorage` instruction. We create `TemporaryStorage`
instructions speculatively when creating an initializing expression, and
may overwrite those instructions with other instructions if it turns out
that a temporary is not required. Instead, wait until we finalize the
temporary and create a `Temporary` instruction to register the cleanup.
We already allowed this for reference expressions; this extends the
support to also cover value expressions. This requires a little more
work because the value representation of `T` and `MaybeUnformed(T)`
don't necessarily match in general.
There are a few instructions that import in multiple phases, which
receive the `const_id` and use it to construct multiple constants until
building the final constant value. These include
`AssociatedConstantDecl`, `FunctionDecl`, and `InterfaceDecl`.
Other instructions just construct a constant value in a single attempt,
once all their dependencies are imported. For these instruction types,
avoid importing the non-canonical instruction. Always get the canonical
constant instruction and import that.
Since the constant value of an instruction can have a very different
structure than its non-canonical value, this ensures import has a
consistent structure to work with, by only working with canonical values
as much as possible.
The `VtableDecl` and `VtablePtr` were set up to pass along `const_id`
but do not actually require multiple phases, so they have been changed
to stop passing along the unused (and always empty) `const_id`.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
* Treat `MaybeUnformed` and `partial` as qualifiers, like `const`.
* Allow pointer conversions to add qualifiers.
* Allow unsafe pointer conversions to remove qualifiers.
* Allow conversions on non-reference expressions to drop `const`.
* Allow unsafe conversions on any expression to drop `const`.
* Allow unsafe conversions on non-initializing expressions to drop
`partial`. For initializing expressions, we should initialize the
vptr when dropping `partial`; this is not yet supported so we reject.
* Allow conversions on reference expressions to add `MaybeUnformed`.
* Allow unsafe conversions on reference expressions to drop
`MaybeUnformed`. For non-reference expressions, additional work is
required, because the value / initializing representation may not
match between `T` and `MaybeUnformed(T)`, so those are rejected for
now.
Decouples associated constants from being special cased in let handlers.
Enforces associated constant grammar restrictions in parsing instead of
checking.
Closes#5411
This type has the same object representation as `T`, but always uses a
pointer type as its value representation. No other semantics are
provided for it yet.
When importing a class definition, don't ask for the class layout if the
definition is invalid. Avoids an assertion failure in Clang.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
Added tests for different character types.
`char` is currently not in primitives prelude, so had to use full
prelude.
C++ Interop Demo:
```carbon
// main.carbon
library "Main";
import Cpp inline '''
auto output_char(char c) -> void {
printf("%c", c);
}
''';
fn Run() -> i32 {
let msg: array(Core.Char, 13) =
('H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n');
for (c: Core.Char in msg) {
Cpp.output_char(c);
}
return 0;
}
```
```shell
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link main.o --output=demo
$ ./demo
Hello world!
```
Part of https://github.com/carbon-language/carbon-lang/issues/5263.
Following the direction of #5913, add support for parsing an `unsafe as`
operator. For now, we allow one additional conversion using `unsafe as`
beyond the conversions supported by `as`: we permit pointer conversions
that remove qualifiers, such as `const T*` -> `T*`.
Found by WIP validation for this type of issue ongoing in #5997
I'm not entirely sure how the one test update falls out of this change -
but it is from the same test that I originally reduced the problem from,
which is reassuring.
The reduced test case I investigated the issue with was this:
`a.carbon`:
```
library "lib";
interface I1(Other:! type) {
let Result:! type;
}
```
`b.carbon`:
```
import library "lib";
class T1 { }
impl T1 as I1(Self) where .Result = Self { }
```
The SemIR dump diff looked like this:
```
89c89
< %Main.import_ref.b6f = import_ref Main//lib, inst28 [no loc], unloaded
---
> %Main.import_ref.b6f = import_ref Main//lib, inst27 [no loc], unloaded
96c96
< %Main.import_ref.f7b: @I1.%I1.type (%I1.type.e87) = import_ref Main//lib, inst28 [no loc], loaded [symbolic = @I1.%Self (constants.%Self.c47)]
---
> %Main.import_ref.f7b: @I1.%I1.type (%I1.type.e87) = import_ref Main//lib, inst27 [no loc], loaded [symbolic = @I1.%Self (constants.%Self.c47)]
```
Which is a difference, but given the `inst28`/`inst27` don't appear
anywhere else than these two lines, it doesn't give a terribly
meaningful diff/story about what changed - but perhaps it's
sufficient...
Not sure if this test ^ is sufficiently more interesting than the diff
update already in this patch. If so, happy to add the above as a new
test case.
Open to ideas.
We assume these types have the same representation. For now, that will
only be the case for libc++ on 64-bit targets, because libc++ puts the
size field first, and `Core.String` always uses a 64-bit size field even
on 32-bit targets.
---------
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
We import C++ enum types as Carbon class types as adapters for the
corresponding builtin integer type, and we import enumerator constants
as integer constants of that class type.
No operators are supported on such values for now; eventually once we
start asking Clang to implement operators on C++-owned types, these
types should be handled in the same way. However, they can be converted
to the corresponding integer type with `as` via adapter conversion, and
integer builtin functions can operate on them.
Based on #5948. A couple of tricky parts:
* When generating the C++ side of the thunk, we are given a pointer to
the location to emplace the return value. The only mechanism C++
provides to perform this emplacement is using placement `operator new`,
which requires a library function in the `<new>` header. We handle this
by declaring that library function ourselves, and rely on Clang not
actually needing a definition for it (which the standard library owns).
* On the Carbon side of the thunk, we want to form an initializing
expression as the result of the call. We don't have a way of expressing
in SemIR that an initializing expression performs its initialization by
storing through a pointer, so this PR adds a new initializing
instruction, `InPlaceInit`, to model an initialization that's performed
opaquely in-place.
This is necessary if the source type is an adapter, as we would not
otherwise be able to determine what type it adapts and hence could be
converted to.
Fix the algorithm for importing declarations in dependency order to
properly walk the dependency graph. Add the parent declaration of a
declaration to the dependency set so that we have a parent declaration
context to import a declaration into.
Fixes a crash when attempting to import a class whose parent is not
imported.
Add a `Core.String` class to the prelude representing a string view, and
rename the `String` keyword to `str` and make it evaluate to
`Core.String`.
`Core.String` is represented as a pair of a pointer to a character
(actually, to the first character of a string, but we don't have a way
of modeling that yet) and a size (which should be pointer-width, but is
currently always a `u64` as we don't have a `usize` equivalent yet).
`Core.String` values are generated directly by the toolchain for string
literal expressions.
This follows the direction established at the recent summit, but the
design implemented here has not been through the proposal process yet.
Trying to figure out an easy way to debug semir in the prelude, #5703
removed an option to set `--exclude-dump-file-prefix` to empty. But,
this is probably an improvement over that flow... With this change, it's
possible to add `//@dump-sem-ir-file` to a specific prelude file, and
its full IR will be printed. Additionally, it becomes an option with the
default `--dump-sem-ir-ranges=only` to add `//@dump-sem-ir-file` and get
the full file's IR.
This addresses/avoids the duplicate import of vtables.
I went through a few iterations/etc along the way and left them in the
commit
history for the PR in case any of them are useful to illustrate how I
got here,
or worth revisiting.
Essentially I ended up with a circularity in importing - importing the
class
imported the vtable_decl which imported the virtual functions - and then
pending
specifics of the virtual functions needed the self specific of the
enclosing
class which wasn't ready yet.
Adding ImportRef to the vtable_decl to break the cycle caused me trouble
when
naming the vtable_decl instructions - so I tried making the functions in
the
vtable unloaded ImportRefs instead. That worked, but meant that
importing a
class still was doing O(number of vtable entries) even if the vtable
wasn't
used.
So I revisited the lazy vtable_decl - figured out how to make the naming
work
(when building the vtable_ptr, even though the vtable_decl doesn't have
to be
loaded for the vtable_ptr, I force it to be loaded anyway, to load the
vtable so
it's usable by lowering, etc). And then I could go back to the old
non-lazy
loaded vtable entries (using some loaded ImportRefs in the cases where
we needed
them/had already adopted them).
Then thinking about the VtablePtr instruction, went back/forth on
exactly what
it needed - went from VtablePtr's member being a VtableDecl InstId, to a
ClassId, then back to a VtableId as it was before this patch.
Naming the instructions has one oddity, that the VtableDecl and
VtablePtr
instructions seem to need to add the pending name for the VtableId -
despite not
using the VtableId in their own name - should the inst namer be doing
this work
for parameters of instructions rather than requiring the inst to do it
deliberately? (or am I holding it wrong in some way?)
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
* `\x` escapes are not permitted in character literals
* ASCII control characters (U+0000 .. U+001F) are not permitted in
character literals unless specified with escape sequences.
Generalize the f64 support to support other sizes. Also provide interop
support for `float`, `_Float16`, and `__float128`.
Also lay some groundwork for non-standard floating-point types, though
we don't have any syntax to name them yet.
I noticed while trying to set up an associated constant in the prelude
that we weren't supporting bool value imports; this goes through and
addresses support for simple builtin types.
Array initialization fails on declaration, which seems like a bug but
I'm only documenting it here.
Also fix missing export of `Core.FloatLiteral`
I checked and this doesn't seem to affect #5952, which is doing more
float changes.
The main change here is that a bad type appearing somewhere within a
field or base class of a class shouldn't cause an import of that class
to fail. Instead, only that field or base class becomes inaccessible
from Carbon.
Also improve the way that type importing errors are diagnosed. While we
lose the precision of a diagnostic saying why a type is not supported,
we gain a useful source location for where the type was mentioned in C++
code.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Don't convert to f64 until we know that's the type that we actually
want. Also reimplement the conversion from RealId to FloatId to perform
an exact conversion with a real check for overflow, rather than
performing an approximate conversion via the host `double` type.
Unfortunately, LLVM doesn't expose its integer mantissa and exponent to
APFloat conversion, so we convert the RealId back to a string for now.
The LLVM conversion also detects overflow only if the literal would
round to having an out-of-range exponent, not if the literal is outside
the range of values of the type as the Carbon design expects. It's not
clear to me which rule we actually want here, so for simplicitly I'm
using the LLVM rule for now.
In preparation for adding other floating-point types beyond f64.
* Rename the type.
* Change lowering to lower FloatLiteralType values as the placeholder
`{}` value we use for literals instead of as an LLVM f64.
* Change eval to convert the type as part of a floating point
conversion, so that lowering can lower converted constants properly.
For now we still represent a value of FloatLiteralType as a
double-precision APFloat. (That will need to change so that we can
losslessly convert literals to f80 / f128 values, and so that we can
convert literals to f32 values without double-rounding.)
We add a virtual node (`CompileTimeBindingPatternStart`) as the first
child of `CompileTimeBindingPattern` which holds the identifier
underneath it, so that it is checked just before the type expression of
the `CompileTimeBindingPattern`. When we reach this virtual node during
check, we add `.Self` as a name in the current scope, and when we reach
`CompileTimeBindingPattern` we remove it from scope, which ensures it's
present during only the checking of the type expression for the compile
time pattern.
At the moment the `.Self` has a different type (it's a `TypeType`) than
other `.Self` in the facet type (which are a single `FacetType`), but
the intention is to immediately substitute it out of the facet type
entirely, replacing it with a reference to the compile time binding (a
`BindSymbolicName`) itself. A TODO has been added for this.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
The self access is important; for the test `generic_class.carbon` being
added to `toolchain/check/testdata/class/destroy_calls.carbon`, it was
using `%T.as.Destroy` instead of `%D.as.Destroy`, indicating the default
blank impl was being used instead of the type-specific version. That
test is trying to focus on the issue, but the delta is visible in a
couple other files in this PR, for example
`toolchain/check/testdata/class/generic/init.carbon`.
I'm separately working on getting rid of the default impl, which is how
I noticed this.
Add missing builtins for float compound assignment, for building a
FloatType, and for converting a float literal to FloatType. Switch
`Core.Float` to being a class and add impls for the various
floating-point operators.
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
When an error diagnostic has an unattached location, for example because
the diagnostic points into a file that's in the prelude, use the next
attached location to position the error diagnostic's CHECK line. In
particular, if the error is followed by a note, use the position of the
note to determine where to place the error.
This exposes a general mechanism to do final fixups of the CHECK lines
to individual file_test binaries, which the toolchain's binary uses to
special-case error / warning CHECK lines.
With help from Richard Smith debugging/identifying this.
Hmm - looks like maybe the Self type import ref may have the same
problem? (or at least it seems to have the same quirk in the semir dump,
where the inst id is mentioned in the `import_ref` insts, but is not
defined elsewhere, has no name, and says `[no loc]`. I'll look into that
separately. (hmm, maybe this is just an unloaded ImportRef, actually)
When initializing a C++ thunk parameter:
* If we have an initializing expression, materialize a temporary and
pass its address.
* If we have a reference expression, pass its address directly.
* If we have a value expression with a pointer value representation,
pass the pointer.
* Otherwise, create a new temporary and initialize it with a copy of the
argument, and pass its address.
This makes all `.Self` references in a facet type canonically the same
(which will remain true iff they refer to the same `Self` type in the
future), removing the need to do more complex comparisons between them
using the EntityName, interface, and index. This allows the comparison
of types containing `.Self` references to be done correctly regardless
of where the `.Self` appears, as such type expressions will all be
canonically equal if they otherwise equal now, regardless of whether
they are written in the context where `.Self` could have seen different
`Self` facet types.
In order to retain access to constraints on a base `.Self` facet type,
in the case of applying `where` to an existing facet type, we:
- Give the base facet type as a `RequirementBaseFacetType` constraint so
that eval of `WhereExpr` can find and copy all the constraints off of
it.
- Introduce eager/early rewrite constraint resolution, which allows a
constraint to eagerly resolve access to earlier rewrite constraints
(`where .A = () and .B = .A` is eagerly transformed into `where .A = ()
and .B = ()`) before the full constraint resolution step. This allows
use of rewrite constraints in larger type expressions, such as `where .A
= () and .B = C(.A)` and `C` will know that the argument is `()`.
Use it to dump the AST that includes a generated C++ thunk.
Based on #5917.
Also added printing of the full actual text when check fails to make
debugging easier.
Changed line replacement to allow removing complete lines.
Part of #5514.
I was thinking about this for destruction, which I may not be able to
use it for, but still think this may be a good change to keep features
consistent.
toolchain/check/testdata/builtins/char/basics.carbon and
toolchain/lower/testdata/builtins/char.carbon are probably the most
interesting tests here. The parse tests is required because this adds a
new node kind, and we need coverage of it; but the attached info is
minor. There's a fair amount of test churn here because I'm adding the
Core.Char and Core.CharLiteral types as new singletons.
My intent here is that `CharId` is always a unicode code point, even
when the type is a `Char` and thus must be a single UTF-8 code unit
(single byte). This mainly means the stored value of a `CharValue` can
be printed internally without knowing the type.
---------
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Similar to 26ec78ec00 - vtable entries
can't be unattached symbolic constants, because if they are they can't
be `GetValueInSpecific`d because they lack the context for their
generic/specific.
Importing mostly wants to make/import things as unattached constants -
but `ImportRef` supports attached constants, so use those - but we don't
need the laziness, so use `LoadedImportRef`.
When the C++ function has a parameter that is not a pointer and not a
signed integer of 32 or 64 bits, generate a thunk.
Terminology:
* Callee function: The C++ function we actually want to call.
* Thunk function: The C++ function we generated that calls the callee
function.
* A simple ABI type, for now, is one of:
* A pointer
* signed integer with 32 bits
* signed integer with 64 bits
The thunk function is marked `always_inline` and uses the `asm`
attribute to set its mangled to the callee function mangled name
suffixed with `".carbon_thunk"`.
When importing a C++ function, we decide whether calling it requires a
thunk and if so we generate it and import it as well, which is currently
a recursive call.
When calling the thunk function, we initialize a temporary storage for
each non simple ABI parameter type and take its address. This can be
optimized when the variable is already in storage.
Not supported yet:
* Functions with non void return values.
* Member methods.
Moved unsigned int param test from `arithmetic_types_direct.carbon` to
`arithmetic_types_bridged.carbon`, since only signed integers aren't
bridged using a thunk.
C++ Interop Demo:
```c++
// hello_world.h
struct S {
S() {}
S(const S&) { x = 1; }
int x;
};
void hello_world(S s);
```
```c++
// hello_world.cpp
#include "hello_world.h"
#include <cstdio>
void hello_world2(S s) { printf("hello_world2: %d\n", s.x); }
void hello_world(S s) {
printf("hello_world: %d\n", s.x);
hello_world2(s);
}
```
```carbon
// main.carbon
library "Main";
import Cpp library "hello_world.h";
fn Run() -> i32 {
var s : Cpp.S;
Cpp.hello_world(s);
return 0;
}
```
```shell
$ clang -c hello_world.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link hello_world.o main.o --output=demo
$ ./demo
hello_world: 1
hello_world2: 1
```
Before this change (no thunk - copy constructor not called when calling
`hello_world()`):
```shell
$ ./demo
hello_world: -1219172304
hello_world2: 1
```
This adds support for importing C++ code directly from source rather
than via a `#include`.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>