summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2018-06-03 14:57:05 +0800
committerJohn Hodge <tpg@ucc.asn.au>2018-06-03 14:57:05 +0800
commitbf8f8b4b4a9fe273451be59f68acafbe61968b83 (patch)
tree82993550cb3c88de0edbd55d79e4ea8e8cefffac
parent39b3cf53798683e496804f8322da2254b10850f4 (diff)
parenta7fb27789a2b34543851d207120e2c0001ee9c27 (diff)
downloadmrust-bf8f8b4b4a9fe273451be59f68acafbe61968b83.tar.gz
Merge branch 'master' of https://github.com/thepowersgang/mrustc
-rw-r--r--.travis.yml48
-rw-r--r--Makefile7
-rw-r--r--Notes/BorrowChecker.md22
-rw-r--r--disabled_tests_run-pass.txt109
-rw-r--r--docs/running.md113
-rw-r--r--docs/target.md4
-rw-r--r--minicargo.mk62
-rw-r--r--script-overrides/stable-1.19.0-linux/build_libc.txt3
-rw-r--r--script-overrides/stable-1.19.0-linux/build_std.txt2
-rw-r--r--script-overrides/stable-1.19.0-macos/build_compiler_builtins.txt1
-rw-r--r--script-overrides/stable-1.19.0-macos/build_libc.txt3
-rw-r--r--script-overrides/stable-1.19.0-macos/build_rustc_asan.txt0
-rw-r--r--script-overrides/stable-1.19.0-macos/build_rustc_lsan.txt0
-rw-r--r--script-overrides/stable-1.19.0-macos/build_rustc_msan.txt0
-rw-r--r--script-overrides/stable-1.19.0-macos/build_rustc_tsan.txt0
-rw-r--r--script-overrides/stable-1.19.0-macos/build_std.txt5
-rw-r--r--script-overrides/stable-1.19.0-macos/build_unwind.txt1
-rw-r--r--src/ast/ast.cpp75
-rw-r--r--src/ast/ast.hpp78
-rw-r--r--src/ast/attrs.hpp122
-rw-r--r--src/ast/crate.cpp6
-rw-r--r--src/ast/crate.hpp2
-rw-r--r--src/ast/dump.cpp12
-rw-r--r--src/ast/expr.hpp12
-rw-r--r--src/ast/generics.hpp74
-rw-r--r--src/ast/item.hpp6
-rw-r--r--src/ast/path.hpp6
-rw-r--r--src/ast/pattern.cpp20
-rw-r--r--src/ast/pattern.hpp49
-rw-r--r--src/ast/types.cpp35
-rw-r--r--src/ast/types.hpp93
-rw-r--r--src/expand/cfg.cpp20
-rw-r--r--src/expand/cfg.hpp2
-rw-r--r--src/expand/crate_tags.cpp10
-rw-r--r--src/expand/derive.cpp281
-rw-r--r--src/expand/lang_item.cpp8
-rw-r--r--src/expand/macro_rules.cpp6
-rw-r--r--src/expand/mod.cpp41
-rw-r--r--src/expand/proc_macro.cpp56
-rw-r--r--src/expand/std_prelude.cpp10
-rw-r--r--src/expand/test.cpp6
-rw-r--r--src/hir/deserialise.cpp44
-rw-r--r--src/hir/dump.cpp3
-rw-r--r--src/hir/expr.hpp12
-rw-r--r--src/hir/from_ast.cpp131
-rw-r--r--src/hir/path.hpp1
-rw-r--r--src/hir/serialise.cpp42
-rw-r--r--src/hir/type.cpp10
-rw-r--r--src/hir/type.hpp44
-rw-r--r--src/hir_conv/bind.cpp4
-rw-r--r--src/hir_conv/constant_evaluation.cpp37
-rw-r--r--src/hir_conv/expand_type.cpp4
-rw-r--r--src/hir_expand/closures.cpp2
-rw-r--r--src/hir_typeck/helpers.cpp15
-rw-r--r--src/hir_typeck/helpers.hpp2
-rw-r--r--src/include/debug.hpp7
-rw-r--r--src/include/serialise.hpp222
-rw-r--r--src/include/serialiser_texttree.hpp67
-rw-r--r--src/include/span.hpp2
-rw-r--r--src/include/string_view.hpp89
-rw-r--r--src/include/synext_decorator.hpp22
-rw-r--r--src/macro_rules/eval.cpp5
-rw-r--r--src/macro_rules/macro_rules.hpp24
-rw-r--r--src/macro_rules/mod.cpp67
-rw-r--r--src/main.cpp292
-rw-r--r--src/mir/cleanup.cpp10
-rw-r--r--src/mir/from_hir.cpp4
-rw-r--r--src/mir/main_bindings.hpp2
-rw-r--r--src/mir/optimise.cpp6
-rw-r--r--src/parse/common.hpp12
-rw-r--r--src/parse/expr.cpp27
-rw-r--r--src/parse/interpolated_fragment.cpp8
-rw-r--r--src/parse/interpolated_fragment.hpp4
-rw-r--r--src/parse/paths.cpp4
-rw-r--r--src/parse/pattern.cpp80
-rw-r--r--src/parse/root.cpp231
-rw-r--r--src/parse/token.cpp100
-rw-r--r--src/parse/token.hpp20
-rw-r--r--src/parse/tokenstream.cpp6
-rw-r--r--src/parse/tokenstream.hpp4
-rw-r--r--src/parse/types.cpp97
-rw-r--r--src/resolve/absolute.cpp125
-rw-r--r--src/serialise.cpp264
-rw-r--r--src/trans/codegen_c.cpp46
-rw-r--r--src/trans/codegen_mmir.cpp193
-rw-r--r--src/trans/enumerate.cpp5
-rw-r--r--src/trans/main_bindings.hpp7
-rw-r--r--src/trans/mangling.hpp2
-rw-r--r--src/trans/target.cpp144
-rw-r--r--src/trans/target.hpp12
-rwxr-xr-xtest_smiri.sh9
-rw-r--r--tools/common/debug.cpp8
-rw-r--r--tools/common/debug.h1
-rw-r--r--tools/common/target_detect.h66
-rw-r--r--tools/common/toml.cpp6
-rw-r--r--tools/minicargo/Makefile2
-rw-r--r--tools/minicargo/build.cpp48
-rw-r--r--tools/minicargo/main.cpp28
-rw-r--r--tools/minicargo/manifest.cpp2
-rw-r--r--tools/standalone_miri/Makefile44
-rw-r--r--tools/standalone_miri/debug.cpp35
-rw-r--r--tools/standalone_miri/debug.hpp18
-rw-r--r--tools/standalone_miri/hir_sim.cpp269
-rw-r--r--tools/standalone_miri/hir_sim.hpp43
-rw-r--r--tools/standalone_miri/lex.cpp29
-rw-r--r--tools/standalone_miri/lex.hpp1
-rw-r--r--tools/standalone_miri/main.cpp1971
-rw-r--r--tools/standalone_miri/mir.cpp1
-rw-r--r--tools/standalone_miri/miri.cpp2305
-rw-r--r--tools/standalone_miri/miri.hpp79
-rw-r--r--tools/standalone_miri/module_tree.cpp214
-rw-r--r--tools/standalone_miri/module_tree.hpp17
-rw-r--r--tools/standalone_miri/value.cpp445
-rw-r--r--tools/standalone_miri/value.hpp379
-rw-r--r--tools/testrunner/main.cpp29
115 files changed, 5774 insertions, 4246 deletions
diff --git a/.travis.yml b/.travis.yml
index 0dc40d9a..d58427ef 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,31 +1,41 @@
language: cpp
sudo: false
-os: linux
-addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - g++-6
- - zlib1g-dev
- - valgrind
+
+matrix:
+ include:
+ # Linux
+ - os: linux
+ before_install:
+ - export CC=gcc-6
+ - export CXX=g++-6
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - g++-6
+ - zlib1g-dev
+ - valgrind
+ # OSX
+ - os: osx
install:
# Build mrustc
- make RUSTCSRC
- - CC=gcc-6 CXX=g++-6 make -j 2
- - CC=gcc-6 CXX=g++-6 make -C tools/minicargo
+ - make -j 2
+ - make -C tools/minicargo
script:
- - CC=gcc-6 CXX=g++-6 make -f minicargo.mk output/libtest.hir
-# libstd and hello_world
- - CC=gcc-6 make test TAIL_COUNT=2
-# rustc (DISABLED: llvm build)
-# - CC=gcc-6 CXX=g++-6 make -f minicargo.mk output/rustc
+ - set -e
+ - make -f minicargo.mk output/libtest.hir # libstd
+ - make test # hello_world
# Tests
- - CC=gcc-6 CXX=g++-6 make local_tests -k
+ - set +e
+ - make local_tests -k
# - CC=gcc-6 make rust_tests -k
-# cargo
-# - CC=gcc-6 CXX=g++-6 make -f minicargo.mk output/cargo
+# rustc (DISABLED: llvm build)
+# - make -f minicargo.mk output/rustc
+# cargo (DISABLED: why?)
+# - make -f minicargo.mk output/cargo
# - cat output/cargo-build/cargo_dbg.txt
diff --git a/Makefile b/Makefile
index 18415510..1aafecc3 100644
--- a/Makefile
+++ b/Makefile
@@ -33,10 +33,6 @@ RUST_TESTS_FINAL_STAGE ?= ALL
LINKFLAGS := -g
LIBS := -lz
CXXFLAGS := -g -Wall
-# - Only turn on -Werror when running as `tpg` (i.e. me)
-ifeq ($(shell whoami),tpg)
- CXXFLAGS += -Werror
-endif
CXXFLAGS += -std=c++14
#CXXFLAGS += -Wextra
CXXFLAGS += -O2
@@ -74,7 +70,7 @@ OBJDIR = .obj/
BIN := bin/mrustc$(EXESUF)
-OBJ := main.o serialise.o
+OBJ := main.o
OBJ += span.o rc_string.o debug.o ident.o
OBJ += ast/ast.o
OBJ += ast/types.o ast/crate.o ast/path.o ast/expr.o ast/pattern.o
@@ -307,6 +303,7 @@ $(BIN): $(OBJ) tools/bin/common_lib.a
@echo [CXX] -o $@
$V$(CXX) -o $@ $(LINKFLAGS) $(OBJ) tools/bin/common_lib.a $(LIBS)
ifeq ($(OS),Windows_NT)
+else ifeq ($(shell uname -s || echo not),Darwin)
else
objcopy --only-keep-debug $(BIN) $(BIN).debug
objcopy --add-gnu-debuglink=$(BIN).debug $(BIN)
diff --git a/Notes/BorrowChecker.md b/Notes/BorrowChecker.md
index 78b46ff5..d01fcb40 100644
--- a/Notes/BorrowChecker.md
+++ b/Notes/BorrowChecker.md
@@ -1,3 +1,25 @@
+
+Lifetime Annotations
+====================
+
+Problems
+--------
+
+Higher-ranked bounds (lifetimes) can be nested, and typecheck/inferrence can change that nesting after resolve
+- Potential solution: each HRB block (`for<...>`) is numbered within one of three scopes, the impl scope, item scope, and body scope.
+ - Impl scope is for bounds that are visible for the entire `impl` or type block
+ - Item scope is for bounds visible within the current impl item (`fn`, `type`, ...)
+ - Body scope is for bounds within the body of a function (e.g. in type annotations)
+ - Each of these scopes specifies a prefix to the binding IDs, similar to how currently there's three prefixes for generics (impl, item, placeholder)
+
+Region inferrence
+- To what extent does type inferrene play into lifetime inferrence? Can lifetimes be inferred as a second pass after
+ types are concretely known, or do they play into each other?
+
+
+Notes on Borrowck
+=================
+
- On borrow, calculate lifetime of asignment (using existing lifetime code)
- Ignore reborrows?
- Visit all statements in that lifetime and locate places where the borrow is propagated/stored
diff --git a/disabled_tests_run-pass.txt b/disabled_tests_run-pass.txt
index 59b4fbcb..25b0b838 100644
--- a/disabled_tests_run-pass.txt
+++ b/disabled_tests_run-pass.txt
@@ -72,8 +72,6 @@ lex-bare-cr-nondoc-comment # Don't treat \r as a new line
# PARSE
align-struct # repr(align(2)) - Need to support integers in attributes
catch-expr # MISSING: `do catch {}` syntax
-issue-37733 # for<'a> in types
-issue-39089 # for<'a> in optional traits
loop-break-value # TODO: Handle loop labels in expression position.
match-range # TODO: Exlusive ranges in patterns
paths-in-macro-invocations # TODO: Handle path macros at root.
@@ -120,6 +118,23 @@ trait-item-inside-macro # TODO: Allow macro invocations in traits
try-operator-custom # TODO: use the ops::Try trait instead of try! desugar
type-macros-simple # macro_rules ordering with nested items
+# RESOLVE
+issue-33687 # Calling a unit-like struct with Fn* traits - "Pointed struct in TupleVariant (::Test) isn't a Tuple"
+static-function-pointer-xc # Calling a static function pointer
+const-block # ^
+const-block-cross-crate-fn # ^
+const-block-item # ^
+rfc1623 # ^
+static-function-pointer # ^
+issue-17718 # ^ (const here, but same idea)
+issue-27890 # ^
+empty-struct-braces # MISSING: Full support for braced initialisers for unit-like structs/variants
+issue-22546 # ^
+issue-29540 # Errors out on very deep method call list.
+issue-34751 # Treats unit-like structs as refutable patterns
+mir_ascription_coercion # TODO: Either visit expected types, or make a type annotation its own node type
+type-ascription # ^
+
# CONST EVAL
associated-const-type-parameters # TODO: Associated const referred from associated const
check-static-mut-slices # MISSING: "Only shared borrows are allowed in constants"
@@ -163,18 +178,13 @@ issue-2718 # isize enum repr
small-enum-range-edge # i8 enum repr
issue-22258 # BUG: Incorrect handling of trait param defaults
multiple-reprs # BUG: Incorrect handling of multiple reprs
-packed-struct-generic-layout # TODO: repr(packed) - at least error on it!
-packed-struct-generic-size # ^
-packed-struct-layout # ^
-packed-struct-size # ^
-packed-struct-size-xc # ^
-packed-struct-vec # ^
-packed-tuple-struct-layout # ^
-packed-tuple-struct-size # ^
placement-in-syntax # BUG: Can't find impl in optimise
struct-path-associated-type # HUH? `T::A { ... }` struct literal with (bounded) associated const
struct-path-self # TODO: Handle `Self` in patterns
-thread-local-extern-static # TODO: #[no_mangle]
+issue-17170 # TODO: #[repr(simd)]
+simd-size-align # ^
+simd-type # ^
+simd-upgraded # ^
# TYPECHECK
associated-types-doubleendediterator-object # BUG BUG: Validation failed
@@ -232,9 +242,6 @@ fat-ptr-cast # Array unsize missed
issue-20797 # Trait unsize runthrough
issue-26905 # Manual CoerceUnsized not working?
-# None::<T> syntax somewhere (TODO)
-issue-22546
-
# MIR GEN:
issue-18352 # append_from_lit - Match literal Borrow
issue-11940 # ^
@@ -282,17 +289,16 @@ issue-6919 # Handle function pointer from Literal
# TRANS
-enum-discrim-width-stuff # mrustc doesn't calculate enum descriminant sizes based on values.
-enum-discrim-autosizing # ^
-nonzero-enum # ^
-small-enums-with-fields # ^
-type-sizes # ^
-float_math # Missing intrinsic (fadd_fast)
+enum-discrim-autosizing # Incorrect enum descrim auto-selection (0x80 picks i16)
+enum-discrim-width-stuff # ^
+nonzero-enum # No packing of None into invalid inner variants
+type-sizes # Inefficient field packing in enum variants
+float_math # Missing intrinsic (fadd_fast)
issue-38074 # Missing intrinsic (simd_shuffle)
simd-generics # Missing intrinsic (simd_*)
simd-intrinsic-generic-arithmetic # ^
simd-intrinsic-generic-elements # ^
-raw-fat-ptr # Ordering comparisons of raw pointers
+raw-fat-ptr # Ordering comparisons of raw pointers
abi-sysv64-register-usage # asm! register translation
allocator-override # asm! translation - "TODO: Handle asm! output leader 'r'"
i128 # ^
@@ -315,7 +321,6 @@ enum-discrim-manual-sizing # TODO: Enum reprs not being correctly used (signed
enum-univariant-repr # ^
enum-layout-optimization # BUG: Option size optimisation not applied
enum-null-pointer-opt # ^
-nullable-pointer-opt-closures # ^
nullable-pointer-size # ^
explicit-self-generic # BUG: Incorrect method lookup (doesn't try autoderef, picks ExactSizeIterator)
i128-ffi # UNK: i128 is hard (TODO: TRIAGE)
@@ -325,31 +330,18 @@ issue-21058 # BUG: Enumerate doesn't handle data-less trait objects (e.g. `d
issue-25515 # ^
issue-26709 # ^
issue-35815 # ^
-issue-34796 # BUG: Missing vtable type.
+issue-34796 # BUG: Missing vtable type.
mir_calls_to_shims # BUG: Missing functions (bad enumerate?)
newtype # Incorrect error when a struct is used in a function pointer to itself
trans-object-shim # BUG: Doesn't generate `<(Foo) as Foo>::bar` function.
transmute-specialization # BUG: Enumerate hit an opaque type
-type-id-higher-rank # BUG: type_id returns the same value for `for<'a> fn(&'a T)` as `fn(&'static T)`
+type-id-higher-rank # BUG: type_id returns the same value for `for<'a> fn(&'a T)` as `fn(&'static T)`
type-id-higher-rank-2 # ^ (test failed)
unsized3 # BUG: Incorrect dst type annotation for struct containing `str`
utf8_idents # BUG: No escaping of utf8 in symbols, GCC doesn't like this
-
-# RESOLVE
-issue-33687 # Calling a unit-like struct with Fn* traits - "Pointed struct in TupleVariant (::Test) isn't a Tuple"
-static-function-pointer-xc # Calling a static function pointer
-const-block # ^
-const-block-cross-crate-fn # ^
-const-block-item # ^
-rfc1623 # ^
-static-function-pointer # ^
-issue-17718 # ^ (const here, but same idea)
-issue-27890 # ^
-empty-struct-braces # MISSING: Full support for braced initialisers for unit-like structs/variants
-issue-29540 # Errors out on very deep method call list.
-issue-34751 # Treats PhantomData as a refutable pattern
-mir_ascription_coercion # TODO: Either visit expected types, or make a type annotation its own node type
-type-ascription # ^
+abi-sysv64-arg-passing # ERROR: Empty struct arguments to FFI aren't actually empty
+extern-pass-empty # ^
+thread-local-extern-static # TODO: #[no_mangle] on statatic definition
# HIR MISC
xcrate-associated-type-defaults # type_is_specialisable - Handle missing type in impl(0x17e3018) ::"xcrate_associated_type_defaults"::Foo<u32,> for () {}, name = Out
@@ -371,4 +363,41 @@ tls-dtors-are-run-in-a-static-binary # Thread-local destructors aren't being
exec-env # Runtime environment variable
extern-crosscrate # test runner params with no leading space
+# Requires unwinding panics
+unwind-resource
+backtrace
+backtrace-debuginfo
+backtrace-debuginfo-aux
+issue-24313 # Not sure if this is unwinding or TLS problems...
+box-of-array-of-drop-1
+box-of-array-of-drop-2
+catch-unwind-bang
+cleanup-rvalue-temp-during-incomplete-alloc
+drop-trait-enum
+dynamic-drop
+intrinsic-move-val-cleanups
+issue-14875
+issue-25089
+issue-26655
+issue-29485
+issue-29948
+issue-30018-panic
+issue-8460 # .. except it fails because there's no overflow checks
+multi-panic
+nested-vec-3
+panic-handler-chain
+panic-handler-flail-wildly
+panic-handler-set-twice
+panic-in-dtor-drops-fields
+panic-recover-propagate
+reachable-unnameable-items
+slice-panic-1
+slice-panic-2
+task-stderr
+terminate-in-initializer
+test-should-fail-good-message
+unit-like-struct-drop-run
+unwind-unique
+vector-sort-panic-safe
+
# vim: ft=make expandtab ts=4
diff --git a/docs/running.md b/docs/running.md
new file mode 100644
index 00000000..d665a8bd
--- /dev/null
+++ b/docs/running.md
@@ -0,0 +1,113 @@
+
+Running mrustc/minicargo
+========================
+
+The easisest way to compile code with mrustc is to use `minicargo` to build a project using a Cargo.toml file, but if
+you need extra control over the output, `mrustc` can be called directly.
+
+minicargo
+=========
+
+```
+minicargo mycrate/ -L ../libstd_crates --vendor-dir vendored/
+```
+
+The above builds the crate specified by `mycrate/Cargo.toml`, looking for compiled versions of the standard library crates in `../libstd_crates` and pre-downloaded crates.io packages in `vendored/`. The compiled crates (both `mycrate` and any of its dependencies) will be placed in the default location ( `output/`)
+
+Options
+-------
+
+- `--help, -h`
+ - Show basic help
+- `--script-overrides <dir>`
+ - Folder containing `<cratename>.txt` files that are used as if they were the output from that crate's build script (used for building libstd)
+- `--vendor-dir <dir>`
+ - Directory containing extracted crates.io packages required to build the current crate (see [https://crates.io/crates/cargo-vendor](cargo-vendor))
+- `--output-dir,-o <dir>`
+ - Specifies the output directory, used for both dependencies and the final binary.
+- `--target <name>`
+ - Cross-compile for the specified target
+- `-L <dir>`
+ - Add a directory to the crate/library search path
+- `-j <num>`
+ - Run a specified number of build jobs at once
+- `-n`
+ - Do a dry run (print the crates to be compiled, but don't build any of them)
+- `-Z <option>`
+ - Debugging/experiemental options (see below)
+
+Debugging options
+- `-Z emit-mmir`
+ - Use the `mmir` mrustc backend (for use with the "Stanalone MIRI" tool)
+
+
+mrustc
+======
+`mrustc`'s command-line interface is very similar to rustc's, taking a path to the crate root, an output directory/file, and optional library search paths and crate paths.
+
+```
+mrustc mycrate/main.rs -L ../libstd_crates --crate mylib=mylib.hir -o mycrate.exe
+```
+
+The above builds the binary crate rooted at `mycrate/main.rs` and outputs it to `mycrate.exe`. It looks for external
+crates in `../libstd_crates`, but also is told that `extern crate mylib;` should load `mylib.hir`.
+
+Options
+-------
+
+- `-L <dir>`
+ - Search for crate files (`.hir` files) in this directory
+- `-o <filename>`
+ - Write compiler output (library or executable) to this file
+- `-O`
+ - Enable optimistion
+- `-g`
+ - Emit debugging information
+- `--out-dir <dir>`
+ - Specify the output directory (alternative to `-o`)
+- `--extern <crate>=<path>`
+ - Specify the path for a given crate (instead of searching for it)
+- `--crate-tag <str>`
+ - Specify a suffix for symbols and output files
+- `--crate-name <str>`
+ - Override/set the crate name
+- `--crate-type <ty>`
+ - Override/set the crate type (rlib, bin, proc-macro)
+- `--cfg flag`
+ - Set a boolean `#[cfg]`/`cfg!` flag
+- `--cfg flag=\"val\"`
+ - Set a string `#[cfg]`/`cfg!` flag (Note: This can be repeated with the same name, adding extra options each time. You may need to escape the quotes in your shell
+- `--target <name>`
+ - Compile code for the given target (if the name has a slash in it, it's treated as the path to a target file)
+- `--test`
+ - Generate a unit test executable
+- `-C <option>`
+ - Code-generation options (see below)
+- `-Z <option>`
+ - Debugging/experiemental options (see below)
+
+Codegen options
+- `-C emit-build-command=<filename>`
+ - Write the command that would be used to invoke the C compiler to the specified file
+- `-C codegen-type=<type>`
+ - Switch codegen backends. Valid options are: `c` (The normal C backend), `mmir` (Monomorphised MIR, used for `standalone_miri`)
+- `-C emit-depfile=<filename>`
+ - Write out a makefile-style dependency file for the crate
+
+Debugging Options
+- `-Z disable-mir-opt`
+ - Disable MIR optimisations (while still enabling optimisation in the backend)
+- `-Z full-validate`
+ - Perform expensive MIR validation before translation (can spot codegen bugs, but is VERY slow)
+- `-Z full-validate-early`
+ - Perform expensive MIR validation before optimisation (even slower)
+- `-Z dump-ast`
+ - Dump the AST after expansion and name resolution complete
+- `-Z dump-hir`
+ - Dump the HIR (simplified and resolved AST) at various stages in compilation
+- `-Z dump-mir`
+ - Dump the MIR for all functions at various stages in compilation
+- `-Z stop-after=<stage>`
+ - Stop compilation after the specified stage. Valid options are `parse`, `expand`, `resolve`, `typeck`, and `mir`
+
+
diff --git a/docs/target.md b/docs/target.md
index 6b5b088d..4b6b5920 100644
--- a/docs/target.md
+++ b/docs/target.md
@@ -6,7 +6,7 @@ Mrustc supports a few targets out of the box (of varying levels of usablity), th
`src/trans/target.cpp`. If the built-in targets aren't suitable, a custom target can be specified with the help of a
custom target toml file.
-To specify a target when running `mrustc` (or `minicaro`), pass `--target <triple>` or `--target
+To specify a target when running `mrustc` (or `minicargo`), pass `--target <triple>` or `--target
./path/to/target.toml` (the presence of a slash, backwards or forwards, is what determines if the target is treated as
a custom target file.
@@ -27,7 +27,7 @@ variant = "gnu"
target = "arm-linux-gnu"
```
-Recreation of the `i586-windows-gnu` target (with architecture)
+Recreation of the `i586-windows-gnu` target (with architecture definition)
```toml
[target]
family = "windows"
diff --git a/minicargo.mk b/minicargo.mk
index c82474f9..aee2483a 100644
--- a/minicargo.mk
+++ b/minicargo.mk
@@ -1,9 +1,29 @@
+#
+#
+#
+OUTDIR_SUF ?=
+MMIR ?=
RUSTC_CHANNEL ?= stable
RUSTC_VERSION ?= 1.19.0
+ifeq ($(OS),Windows_NT)
+else ifeq ($(shell uname -s || echo not),Darwin)
+OVERRIDE_SUFFIX ?= -macos
+else
OVERRIDE_SUFFIX ?= -linux
-OUTDIR := output/
+endif
PARLEVEL ?= 1
+MINICARGO_FLAGS ?=
+
+ifneq ($(MMIR),)
+ OUTDIR_SUF := -mmir
+ MINICARGO_FLAGS += -Z emit-mmir
+endif
+ifneq ($(PARLEVEL),1)
+ MINICARGO_FLAGS += -j $(PARLEVEL)
+endif
+
+OUTDIR := output$(OUTDIR_SUF)/
MRUSTC := bin/mrustc
MINICARGO := tools/bin/minicargo
@@ -30,31 +50,31 @@ LIBS: $(OUTDIR)libstd.hir $(OUTDIR)libtest.hir $(OUTDIR)libpanic_unwind.hir $(OU
$(MRUSTC):
$(MAKE) -f Makefile all
- test -e $@
+ @test -e $@
$(MINICARGO):
$(MAKE) -C tools/minicargo/
- test -e $@
+ @test -e $@
# Standard library crates
# - libstd, libpanic_unwind, libtest and libgetopts
# - libproc_macro (mrustc)
$(OUTDIR)libstd.hir: $(MRUSTC) $(MINICARGO)
- $(MINICARGO) $(RUSTCSRC)src/libstd --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) -j $(PARLEVEL)
- test -e $@
+ $(MINICARGO) $(RUSTCSRC)src/libstd --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
+ @test -e $@
$(OUTDIR)libpanic_unwind.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir
- $(MINICARGO) $(RUSTCSRC)src/libpanic_unwind --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) -j $(PARLEVEL)
- test -e $@
+ $(MINICARGO) $(RUSTCSRC)src/libpanic_unwind --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
+ @test -e $@
$(OUTDIR)libtest.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir $(OUTDIR)libpanic_unwind.hir
- $(MINICARGO) $(RUSTCSRC)src/libtest --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR) -j $(PARLEVEL)
- test -e $@
+ $(MINICARGO) $(RUSTCSRC)src/libtest --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
+ @test -e $@
$(OUTDIR)libgetopts.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir
- $(MINICARGO) $(RUSTCSRC)src/libgetopts --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) -j $(PARLEVEL)
- test -e $@
+ $(MINICARGO) $(RUSTCSRC)src/libgetopts --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
+ @test -e $@
# MRustC custom version of libproc_macro
$(OUTDIR)libproc_macro.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir
- $(MINICARGO) lib/libproc_macro --output-dir $(OUTDIR)
- test -e $@
+ $(MINICARGO) lib/libproc_macro --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
+ @test -e $@
RUSTC_ENV_VARS := CFG_COMPILER_HOST_TRIPLE=$(RUSTC_TARGET)
RUSTC_ENV_VARS += LLVM_CONFIG=$(abspath $(LLVM_CONFIG))
@@ -66,11 +86,11 @@ RUSTC_ENV_VARS += CFG_LIBDIR_RELATIVE=lib
$(OUTDIR)rustc: $(MRUSTC) $(MINICARGO) LIBS $(LLVM_CONFIG)
mkdir -p $(OUTDIR)rustc-build
- $(RUSTC_ENV_VARS) $(MINICARGO) $(RUSTCSRC)src/rustc --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR)rustc-build -L $(OUTDIR) -j $(PARLEVEL)
+ $(RUSTC_ENV_VARS) $(MINICARGO) $(RUSTCSRC)src/rustc --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR)rustc-build -L $(OUTDIR) $(MINICARGO_FLAGS)
cp $(OUTDIR)rustc-build/rustc $(OUTDIR)
$(OUTDIR)cargo: $(MRUSTC) LIBS
mkdir -p $(OUTDIR)cargo-build
- $(MINICARGO) $(RUSTCSRC)src/tools/cargo --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR)cargo-build -L $(OUTDIR) -j $(PARLEVEL)
+ $(MINICARGO) $(RUSTCSRC)src/tools/cargo --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR)cargo-build -L $(OUTDIR) $(MINICARGO_FLAGS)
cp $(OUTDIR)cargo-build/cargo $(OUTDIR)
# Reference $(RUSTCSRC)src/bootstrap/native.rs for these values
@@ -94,14 +114,14 @@ $(RUSTCSRC)build/Makefile: $(RUSTCSRC)src/llvm/CMakeLists.txt
# Developement-only targets
#
$(OUTDIR)rustc-build/librustdoc.hir: $(MRUSTC) LIBS
- $(MINICARGO) $(RUSTCSRC)src/librustdoc --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR)
+ $(MINICARGO) $(RUSTCSRC)src/librustdoc --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
#$(OUTDIR)cargo-build/libserde-1_0_6.hir: $(MRUSTC) LIBS
-# $(MINICARGO) $(RUSTCSRC)src/vendor/serde --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR)
+# $(MINICARGO) $(RUSTCSRC)src/vendor/serde --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
$(OUTDIR)cargo-build/libgit2-0_6_6.hir: $(MRUSTC) LIBS
- $(MINICARGO) $(RUSTCSRC)src/vendor/git2 --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) --features ssh,https,curl,openssl-sys,openssl-probe
+ $(MINICARGO) $(RUSTCSRC)src/vendor/git2 --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) --features ssh,https,curl,openssl-sys,openssl-probe $(MINICARGO_FLAGS)
$(OUTDIR)cargo-build/libserde_json-1_0_2.hir: $(MRUSTC) LIBS
- $(MINICARGO) $(RUSTCSRC)src/vendor/serde_json --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR)
+ $(MINICARGO) $(RUSTCSRC)src/vendor/serde_json --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
$(OUTDIR)cargo-build/libcurl-0_4_6.hir: $(MRUSTC) LIBS
- $(MINICARGO) $(RUSTCSRC)src/vendor/curl --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR)
+ $(MINICARGO) $(RUSTCSRC)src/vendor/curl --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
$(OUTDIR)cargo-build/libterm-0_4_5.hir: $(MRUSTC) LIBS
- $(MINICARGO) $(RUSTCSRC)src/vendor/term --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR)
+ $(MINICARGO) $(RUSTCSRC)src/vendor/term --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
diff --git a/script-overrides/stable-1.19.0-linux/build_libc.txt b/script-overrides/stable-1.19.0-linux/build_libc.txt
index aa2eb983..4de39783 100644
--- a/script-overrides/stable-1.19.0-linux/build_libc.txt
+++ b/script-overrides/stable-1.19.0-linux/build_libc.txt
@@ -1,2 +1,3 @@
+# rustc-1.19.0-src/src/rustc/libc_shim/build.rs
cargo:rustc-cfg=stdbuild
-cargo:rerun-if-changed=build.rs \ No newline at end of file
+cargo:rerun-if-changed=build.rs
diff --git a/script-overrides/stable-1.19.0-linux/build_std.txt b/script-overrides/stable-1.19.0-linux/build_std.txt
index 121e2825..e88dd227 100644
--- a/script-overrides/stable-1.19.0-linux/build_std.txt
+++ b/script-overrides/stable-1.19.0-linux/build_std.txt
@@ -1,4 +1,4 @@
-# TODO: THis is the windows set
+# TODO: Build libbacktrace
cargo:rustc-link-lib=dl
cargo:rustc-link-lib=rt
cargo:rustc-link-lib=pthread
diff --git a/script-overrides/stable-1.19.0-macos/build_compiler_builtins.txt b/script-overrides/stable-1.19.0-macos/build_compiler_builtins.txt
new file mode 100644
index 00000000..06ae3dbf
--- /dev/null
+++ b/script-overrides/stable-1.19.0-macos/build_compiler_builtins.txt
@@ -0,0 +1 @@
+# NOTE: mrustc doesn't need this built fully \ No newline at end of file
diff --git a/script-overrides/stable-1.19.0-macos/build_libc.txt b/script-overrides/stable-1.19.0-macos/build_libc.txt
new file mode 100644
index 00000000..4de39783
--- /dev/null
+++ b/script-overrides/stable-1.19.0-macos/build_libc.txt
@@ -0,0 +1,3 @@
+# rustc-1.19.0-src/src/rustc/libc_shim/build.rs
+cargo:rustc-cfg=stdbuild
+cargo:rerun-if-changed=build.rs
diff --git a/script-overrides/stable-1.19.0-macos/build_rustc_asan.txt b/script-overrides/stable-1.19.0-macos/build_rustc_asan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.19.0-macos/build_rustc_asan.txt
diff --git a/script-overrides/stable-1.19.0-macos/build_rustc_lsan.txt b/script-overrides/stable-1.19.0-macos/build_rustc_lsan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.19.0-macos/build_rustc_lsan.txt
diff --git a/script-overrides/stable-1.19.0-macos/build_rustc_msan.txt b/script-overrides/stable-1.19.0-macos/build_rustc_msan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.19.0-macos/build_rustc_msan.txt
diff --git a/script-overrides/stable-1.19.0-macos/build_rustc_tsan.txt b/script-overrides/stable-1.19.0-macos/build_rustc_tsan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.19.0-macos/build_rustc_tsan.txt
diff --git a/script-overrides/stable-1.19.0-macos/build_std.txt b/script-overrides/stable-1.19.0-macos/build_std.txt
new file mode 100644
index 00000000..45d767ae
--- /dev/null
+++ b/script-overrides/stable-1.19.0-macos/build_std.txt
@@ -0,0 +1,5 @@
+cargo:rustc-link-lib=System
+# res_init and friends require -lresolv on macOS/iOS.
+# See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
+cargo:rustc-link-lib=resolv
+
diff --git a/script-overrides/stable-1.19.0-macos/build_unwind.txt b/script-overrides/stable-1.19.0-macos/build_unwind.txt
new file mode 100644
index 00000000..8f49a16c
--- /dev/null
+++ b/script-overrides/stable-1.19.0-macos/build_unwind.txt
@@ -0,0 +1 @@
+# Nothing to do on macos
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index a4825a89..4fdf8f9d 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -8,14 +8,13 @@
#include <iostream>
#include "../parse/parseerror.hpp"
#include <algorithm>
-#include <serialiser_texttree.hpp>
namespace AST {
namespace {
- ::std::vector<MetaItem> clone_mivec(const ::std::vector<MetaItem>& v) {
- ::std::vector<MetaItem> ri;
+ ::std::vector<Attribute> clone_mivec(const ::std::vector<Attribute>& v) {
+ ::std::vector<Attribute> ri;
ri.reserve(v.size());
for(const auto& i : v)
ri.push_back( i.clone() );
@@ -23,19 +22,16 @@ namespace {
}
}
-MetaItems::~MetaItems()
+AttributeList AttributeList::clone() const
{
-}
-MetaItems MetaItems::clone() const
-{
- return MetaItems( m_span, clone_mivec(m_items) );
+ return AttributeList( clone_mivec(m_items) );
}
-void MetaItems::push_back(MetaItem i)
+void AttributeList::push_back(Attribute i)
{
m_items.push_back( ::std::move(i) );
}
-const MetaItem* MetaItems::get(const char *name) const
+const Attribute* AttributeList::get(const char *name) const
{
for( auto& i : m_items ) {
if(i.name() == name) {
@@ -46,23 +42,20 @@ const MetaItem* MetaItems::get(const char *name) const
return 0;
}
-MetaItem::~MetaItem()
+Attribute Attribute::clone() const
{
-}
-MetaItem MetaItem::clone() const
-{
- TU_MATCH(MetaItemData, (m_data), (e),
+ TU_MATCHA( (m_data), (e),
(None,
- return MetaItem(m_name);
+ return Attribute(m_span, m_name);
),
(String,
- return MetaItem(m_name, e.val);
+ return Attribute(m_span, m_name, e.val);
),
(List,
- return MetaItem(m_name, clone_mivec(e.sub_items));
+ return Attribute(m_span, m_name, clone_mivec(e.sub_items));
)
)
- throw ::std::runtime_error("MetaItem::clone - Fell off end");
+ throw ::std::runtime_error("Attribute::clone - Fell off end");
}
StructItem StructItem::clone() const
@@ -109,16 +102,16 @@ Function Function::clone() const
return rv;
}
-void Trait::add_type(::std::string name, MetaItems attrs, TypeRef type) {
+void Trait::add_type(::std::string name, AttributeList attrs, TypeRef type) {
m_items.push_back( Named<Item>(mv$(name), Item::make_Type({TypeAlias(GenericParams(), mv$(type))}), true) );
m_items.back().data.attrs = mv$(attrs);
}
-void Trait::add_function(::std::string name, MetaItems attrs, Function fcn) {
+void Trait::add_function(::std::string name, AttributeList attrs, Function fcn) {
DEBUG("trait fn " << name);
m_items.push_back( Named<Item>(mv$(name), Item::make_Function({mv$(fcn)}), true) );
m_items.back().data.attrs = mv$(attrs);
}
-void Trait::add_static(::std::string name, MetaItems attrs, Static v) {
+void Trait::add_static(::std::string name, AttributeList attrs, Static v) {
m_items.push_back( Named<Item>(mv$(name), Item::make_Static({mv$(v)}), true) );
m_items.back().data.attrs = mv$(attrs);
}
@@ -301,18 +294,18 @@ void Module::add_item( Named<Item> named_item ) {
DEBUG(m_my_path << "::" << i.name << " = " << i.data.tag_str() << ", attrs = " << i.data.attrs);
}
}
-void Module::add_item(bool is_pub, ::std::string name, Item it, MetaItems attrs) {
+void Module::add_item(bool is_pub, ::std::string name, Item it, AttributeList attrs) {
it.attrs = mv$(attrs);
add_item( Named<Item>( mv$(name), mv$(it), is_pub ) );
}
-void Module::add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, MetaItems attrs) {
+void Module::add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, AttributeList attrs) {
this->add_item( is_public, imp_name, Item::make_Crate({mv$(ext_name)}), mv$(attrs) );
}
-void Module::add_alias(bool is_public, UseStmt us, ::std::string name, MetaItems attrs) {
+void Module::add_alias(bool is_public, UseStmt us, ::std::string name, AttributeList attrs) {
this->add_item( is_public, mv$(name), Item(mv$(us)), mv$(attrs) );
}
void Module::add_macro_invocation(MacroInvocation item) {
- this->add_item( false, "", Item( mv$(item) ), ::AST::MetaItems {} );
+ this->add_item( false, "", Item( mv$(item) ), ::AST::AttributeList {} );
}
void Module::add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro) {
m_macros.push_back( Named<MacroRulesPtr>( mv$(name), mv$(macro), is_exported ) );
@@ -385,10 +378,31 @@ Item Item::clone() const
//os << ")";
return os;
}
+::std::ostream& operator<<(::std::ostream& os, const LifetimeParam& p)
+{
+ os << "'" << p.m_name;
+ return os;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const HigherRankedBounds& x)
+{
+ if( x.m_lifetimes.empty() ) {
+ return os;
+ }
+ os << "for<";
+ for(const auto& l : x.m_lifetimes)
+ os << "'" << l << ",";
+ os << "> ";
+ return os;
+}
+
::std::ostream& operator<<(::std::ostream& os, const GenericBound& x)
{
TU_MATCH(GenericBound, (x), (ent),
+ (None,
+ os << "/*-*/";
+ ),
(Lifetime,
os << "'" << ent.test << ": '" << ent.bound;
),
@@ -396,14 +410,7 @@ Item Item::clone() const
os << ent.type << ": '" << ent.bound;
),
(IsTrait,
- if( ! ent.hrls.empty() )
- {
- os << "for<";
- for(const auto& l : ent.hrls)
- os << "'" << l;
- os << ">";
- }
- os << ent.type << ": " << ent.trait;
+ os << ent.outer_hrbs << ent.type << ": " << ent.inner_hrbs << ent.trait;
),
(MaybeTrait,
os << ent.type << ": ?" << ent.trait;
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp
index 6b729f8c..241b51d7 100644
--- a/src/ast/ast.hpp
+++ b/src/ast/ast.hpp
@@ -19,7 +19,6 @@
#include "../parse/tokentree.hpp"
#include "types.hpp"
-#include <serialise.hpp>
#include <ast/pattern.hpp>
#include <ast/attrs.hpp>
@@ -51,14 +50,14 @@ enum eItemType
struct StructItem
{
- ::AST::MetaItems m_attrs;
+ ::AST::AttributeList m_attrs;
bool m_is_public;
::std::string m_name;
TypeRef m_type;
//StructItem() {}
- StructItem(::AST::MetaItems attrs, bool is_pub, ::std::string name, TypeRef ty):
+ StructItem(::AST::AttributeList attrs, bool is_pub, ::std::string name, TypeRef ty):
m_attrs( mv$(attrs) ),
m_is_public(is_pub),
m_name( mv$(name) ),
@@ -75,13 +74,13 @@ struct StructItem
struct TupleItem
{
- ::AST::MetaItems m_attrs;
+ ::AST::AttributeList m_attrs;
bool m_is_public;
TypeRef m_type;
//TupleItem() {}
- TupleItem(::AST::MetaItems attrs, bool is_pub, TypeRef ty):
+ TupleItem(::AST::AttributeList attrs, bool is_pub, TypeRef ty):
m_attrs( mv$(attrs) ),
m_is_public(is_pub),
m_type( mv$(ty) )
@@ -129,9 +128,6 @@ private:
TypeRef m_type;
Expr m_value;
public:
- //Static():
- // m_class(CONST)
- //{}
Static(Class s_class, TypeRef type, Expr value):
m_class(s_class),
m_type( move(type) ),
@@ -155,13 +151,11 @@ public:
private:
Span m_span;
- //::std::string m_lifetime;
GenericParams m_params;
Expr m_code;
TypeRef m_rettype;
Arglist m_args;
- // TODO: ABI, const, and unsafe
::std::string m_abi;
bool m_is_const;
bool m_is_unsafe;
@@ -172,7 +166,6 @@ public:
Function(Function&&) = default;
Function& operator=(Function&&) = default;
- //Function() {}
Function(Span sp, GenericParams params, ::std::string abi, bool is_unsafe, bool is_const, bool is_variadic, TypeRef ret_type, Arglist args);
void set_code(Expr code) { m_code = ::std::move(code); }
@@ -197,35 +190,40 @@ public:
class Trait
{
GenericParams m_params;
- ::std::vector< Spanned<AST::Path> > m_supertraits;
+ ::std::vector< Spanned<Type_TraitPath> > m_supertraits;
bool m_is_marker;
+ bool m_is_unsafe;
NamedList<Item> m_items;
public:
Trait():
- m_is_marker(false)
+ m_is_marker(false),
+ m_is_unsafe(false)
{}
- Trait(GenericParams params, ::std::vector< Spanned<Path> > supertraits):
+ Trait(GenericParams params, ::std::vector< Spanned<Type_TraitPath> > supertraits):
m_params( mv$(params) ),
m_supertraits( mv$(supertraits) ),
- m_is_marker(false)
+ m_is_marker(false),
+ m_is_unsafe(false)
{
}
const GenericParams& params() const { return m_params; }
GenericParams& params() { return m_params; }
- const ::std::vector<Spanned<Path> >& supertraits() const { return m_supertraits; }
- ::std::vector<Spanned<Path> >& supertraits() { return m_supertraits; }
+ const ::std::vector<Spanned<Type_TraitPath> >& supertraits() const { return m_supertraits; }
+ ::std::vector<Spanned<Type_TraitPath> >& supertraits() { return m_supertraits; }
const NamedList<Item>& items() const { return m_items; }
NamedList<Item>& items() { return m_items; }
- void add_type(::std::string name, MetaItems attrs, TypeRef type);
- void add_function(::std::string name, MetaItems attrs, Function fcn);
- void add_static(::std::string name, MetaItems attrs, Static v);
+ void add_type(::std::string name, AttributeList attrs, TypeRef type);
+ void add_function(::std::string name, AttributeList attrs, Function fcn);
+ void add_static(::std::string name, AttributeList attrs, Static v);
void set_is_marker();
bool is_marker() const;
+ void set_is_unsafe() { m_is_unsafe = true; }
+ bool is_unsafe() const { return m_is_unsafe; }
bool has_named_item(const ::std::string& name, bool& out_is_fcn) const;
@@ -252,7 +250,7 @@ TAGGED_UNION_EX(EnumVariantData, (), Value,
struct EnumVariant
{
- MetaItems m_attrs;
+ AttributeList m_attrs;
::std::string m_name;
EnumVariantData m_data;
@@ -260,21 +258,21 @@ struct EnumVariant
{
}
- EnumVariant(MetaItems attrs, ::std::string name, Expr&& value):
+ EnumVariant(AttributeList attrs, ::std::string name, Expr&& value):
m_attrs( mv$(attrs) ),
m_name( mv$(name) ),
m_data( EnumVariantData::make_Value({mv$(value)}) )
{
}
- EnumVariant(MetaItems attrs, ::std::string name, ::std::vector<TypeRef> sub_types):
+ EnumVariant(AttributeList attrs, ::std::string name, ::std::vector<TypeRef> sub_types):
m_attrs( mv$(attrs) ),
m_name( ::std::move(name) ),
m_data( EnumVariantData::make_Tuple( {mv$(sub_types)} ) )
{
}
- EnumVariant(MetaItems attrs, ::std::string name, ::std::vector<StructItem> fields):
+ EnumVariant(AttributeList attrs, ::std::string name, ::std::vector<StructItem> fields):
m_attrs( mv$(attrs) ),
m_name( ::std::move(name) ),
m_data( EnumVariantData::make_Struct( {mv$(fields)} ) )
@@ -380,27 +378,29 @@ public:
class ImplDef
{
- Span m_span;
- MetaItems m_attrs;
+ AttributeList m_attrs;
+ bool m_is_unsafe;
GenericParams m_params;
Spanned<Path> m_trait;
TypeRef m_type;
public:
- //ImplDef() {}
- ImplDef(ImplDef&&) /*noexcept*/ = default;
- ImplDef(Span sp, MetaItems attrs, GenericParams params, Spanned<Path> trait_type, TypeRef impl_type):
- m_span( mv$(sp) ),
+ ImplDef(AttributeList attrs, GenericParams params, Spanned<Path> trait_type, TypeRef impl_type):
m_attrs( mv$(attrs) ),
+ m_is_unsafe( false ),
m_params( mv$(params) ),
m_trait( mv$(trait_type) ),
m_type( mv$(impl_type) )
{}
+
+ ImplDef(ImplDef&&) /*noexcept*/ = default;
ImplDef& operator=(ImplDef&&) = default;
+ void set_is_unsafe() { m_is_unsafe = true; }
+ bool is_unsafe() const { return m_is_unsafe; }
+
// Accessors
- const Span& span() const { return m_span; }
- const MetaItems& attrs() const { return m_attrs; }
- MetaItems& attrs() { return m_attrs; }
+ const AttributeList& attrs() const { return m_attrs; }
+ AttributeList& attrs() { return m_attrs; }
const GenericParams& params() const { return m_params; }
GenericParams& params() { return m_params; }
@@ -426,7 +426,6 @@ public:
private:
ImplDef m_def;
- Span m_span;
::std::vector< ImplItem > m_items;
//NamedList<TypeRef> m_types;
@@ -434,7 +433,6 @@ private:
//NamedList<Static> m_statics;
public:
- //Impl() {}
Impl(Impl&&) /*noexcept*/ = default;
Impl(ImplDef def):
m_def( mv$(def) )
@@ -464,8 +462,6 @@ struct UseStmt
::AST::Path path;
::AST::PathBinding alt_binding;
- UseStmt()
- {}
UseStmt(Span sp, Path p):
sp(sp),
path(p)
@@ -553,9 +549,9 @@ public:
::std::shared_ptr<AST::Module> add_anon();
void add_item(Named<Item> item);
- void add_item(bool is_pub, ::std::string name, Item it, MetaItems attrs);
- void add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, MetaItems attrs);
- void add_alias(bool is_public, UseStmt path, ::std::string name, MetaItems attrs);
+ void add_item(bool is_pub, ::std::string name, Item it, AttributeList attrs);
+ void add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, AttributeList attrs);
+ void add_alias(bool is_public, UseStmt path, ::std::string name, AttributeList attrs);
void add_macro_invocation(MacroInvocation item);
void add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro);
@@ -609,7 +605,7 @@ TAGGED_UNION_EX(Item, (), None,
(, attrs(mv$(x.attrs))), (attrs = mv$(x.attrs);),
(
public:
- MetaItems attrs;
+ AttributeList attrs;
Span span;
Item clone() const;
diff --git a/src/ast/attrs.hpp b/src/ast/attrs.hpp
index 28bfec96..1926e96a 100644
--- a/src/ast/attrs.hpp
+++ b/src/ast/attrs.hpp
@@ -1,3 +1,10 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * ast/attrs.hpp
+ * - AST Attributes (#[foo] and #![foo])
+ */
#ifndef _AST_ATTRS_HPP_
#define _AST_ATTRS_HPP_
@@ -5,93 +12,132 @@
namespace AST {
//
-class MetaItem;
+class Attribute;
+::std::ostream& operator<<(::std::ostream& os, const Attribute& x);
-class MetaItems
+/// A list of attributes on an item (searchable by the attribute name)
+class AttributeList
{
public:
- Span m_span;
- ::std::vector<MetaItem> m_items;
-
- virtual ~MetaItems();
- MetaItems() {}
- MetaItems(MetaItems&&) = default;
- MetaItems& operator=(MetaItems&&) = default;
- MetaItems(const MetaItems&) = delete;
- MetaItems(Span sp, ::std::vector<MetaItem> items):
- m_span( mv$(sp) ),
+ ::std::vector<Attribute> m_items;
+
+ AttributeList() {}
+ AttributeList(::std::vector<Attribute> items):
m_items( mv$(items) )
{
}
- void push_back(MetaItem i);
+ // Move present
+ AttributeList(AttributeList&&) = default;
+ AttributeList& operator=(AttributeList&&) = default;
+ // No copy assign, but explicit copy
+ explicit AttributeList(const AttributeList&) = default;
+ AttributeList& operator=(const AttributeList&) = delete;
+ // Explicit clone
+ AttributeList clone() const;
- MetaItems clone() const;
+ void push_back(Attribute i);
- MetaItem* get(const char *name) { return const_cast<MetaItem*>( const_cast<const MetaItems*>(this)->get(name)); }
- const MetaItem* get(const char *name) const;
+ const Attribute* get(const char *name) const;
+ Attribute* get(const char *name) {
+ return const_cast<Attribute*>( const_cast<const AttributeList*>(this)->get(name));
+ }
bool has(const char *name) const {
return get(name) != 0;
}
- friend ::std::ostream& operator<<(::std::ostream& os, const MetaItems& x) {
- return os << "[" << x.m_items << "]";
+ friend ::std::ostream& operator<<(::std::ostream& os, const AttributeList& x) {
+ for(const auto& i : x.m_items) {
+ os << "#[" << i << "]";
+ }
+ return os;
}
};
-TAGGED_UNION(MetaItemData, None,
+TAGGED_UNION(AttributeData, None,
(None, struct {}),
(String, struct {
::std::string val;
}),
(List, struct {
- ::std::vector<MetaItem> sub_items;
+ ::std::vector<Attribute> sub_items;
})
);
-class MetaItem
+// An attribute can has a name, and optional data:
+// Data can be:
+// - A parenthesised token tree
+// > In 1.19 this was actually just sub-attributes
+// - an associated (string) literal
+
+class Attribute
{
+ Span m_span;
::std::string m_name;
- MetaItemData m_data;
+ AttributeData m_data;
+ mutable bool m_is_used;
public:
- virtual ~MetaItem();
- MetaItem() {}
- MetaItem(MetaItem&& ) = default;
- MetaItem& operator=(MetaItem&& ) = default;
- MetaItem(::std::string name):
+ Attribute(Span sp, ::std::string name):
+ m_span(::std::move(sp)),
m_name(name),
- m_data( MetaItemData::make_None({}) )
+ m_data( AttributeData::make_None({}) )
{
}
- MetaItem(::std::string name, ::std::string str_val):
+ Attribute(Span sp, ::std::string name, ::std::string str_val):
+ m_span(::std::move(sp)),
m_name(name),
- m_data( MetaItemData::make_String({mv$(str_val)}) )
+ m_data( AttributeData::make_String({mv$(str_val)}) )
{
}
- MetaItem(::std::string name, ::std::vector<MetaItem> items):
+ Attribute(Span sp, ::std::string name, ::std::vector<Attribute> items):
+ m_span(::std::move(sp)),
m_name(name),
- m_data( MetaItemData::make_List({mv$(items)}) )
+ m_data( AttributeData::make_List({mv$(items)}) )
+ {
+ }
+
+ explicit Attribute(const Attribute& x):
+ m_span(x.m_span),
+ m_name(x.m_name),
+ m_is_used(x.m_is_used)
{
+ TU_MATCHA( (x.m_data), (e),
+ (None,
+ ),
+ (String,
+ m_data = AttributeData::make_String({ e.val });
+ ),
+ (List,
+ m_data = AttributeData::make_List({ ::std::vector<Attribute>(e.sub_items) });
+ )
+ )
}
+ Attribute& operator=(const Attribute&& ) = delete;
+ Attribute(Attribute&& ) = default;
+ Attribute& operator=(Attribute&& ) = default;
+ Attribute clone() const;
- MetaItem clone() const;
+ void mark_used() const { m_is_used = true; }
+ bool is_used() const { return m_is_used; }
- void mark_used() {}
+ const Span& span() const { return m_span; }
const ::std::string& name() const { return m_name; }
+ const AttributeData& data() const { return m_data; }
+ // Legacy accessors/checkers
bool has_noarg() const { return m_data.is_None(); }
bool has_string() const { return m_data.is_String(); }
const ::std::string& string() const { return m_data.as_String().val; }
bool has_sub_items() const { return m_data.is_List(); }
- const ::std::vector<MetaItem>& items() const { return m_data.as_List().sub_items; }
- ::std::vector<MetaItem>& items() { return m_data.as_List().sub_items; }
+ const ::std::vector<Attribute>& items() const { return m_data.as_List().sub_items; }
+ ::std::vector<Attribute>& items() { return m_data.as_List().sub_items; }
- friend ::std::ostream& operator<<(::std::ostream& os, const MetaItem& x) {
+ friend ::std::ostream& operator<<(::std::ostream& os, const Attribute& x) {
os << x.m_name;
- TU_MATCH(MetaItemData, (x.m_data), (e),
+ TU_MATCHA( (x.m_data), (e),
(None,
),
(String,
diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp
index 823f7d00..9e4ed2ad 100644
--- a/src/ast/crate.cpp
+++ b/src/ast/crate.cpp
@@ -12,10 +12,10 @@
::std::map<::std::string, ::std::string> AST::g_crate_overrides;
namespace {
- bool check_item_cfg(const ::AST::MetaItems& attrs)
+ bool check_item_cfg(const ::AST::AttributeList& attrs)
{
for(const auto& at : attrs.m_items) {
- if( at.name() == "cfg" && !check_cfg(attrs.m_span, at) ) {
+ if( at.name() == "cfg" && !check_cfg(at.span(), at) ) {
return false;
}
}
@@ -78,7 +78,7 @@ void Crate::load_externs()
if( a.name() == "no_core" )
no_core = true;
if( a.name() == "cfg_attr" && a.items().size() == 2 ) {
- if( check_cfg(this->m_attrs.m_span, a.items().at(0)) )
+ if( check_cfg(a.span(), a.items().at(0)) )
{
const auto& a2 = a.items().at(1);
if( a2.name() == "no_std" )
diff --git a/src/ast/crate.hpp b/src/ast/crate.hpp
index d6628901..bf1758d7 100644
--- a/src/ast/crate.hpp
+++ b/src/ast/crate.hpp
@@ -38,7 +38,7 @@ public:
class Crate
{
public:
- ::AST::MetaItems m_attrs;
+ ::AST::AttributeList m_attrs;
::std::map< ::std::string, ::AST::Path> m_lang_items;
public:
diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp
index 7026f61d..73b332c0 100644
--- a/src/ast/dump.cpp
+++ b/src/ast/dump.cpp
@@ -560,7 +560,7 @@ private:
m_os << ")";
}
- void print_attrs(const AST::MetaItems& attrs);
+ void print_attrs(const AST::AttributeList& attrs);
void print_params(const AST::GenericParams& params);
void print_bounds(const AST::GenericParams& params);
void print_pattern_tuple(const AST::Pattern::TuplePat& v, bool is_refutable);
@@ -579,7 +579,7 @@ void Dump_Rust(const char *filename, const AST::Crate& crate)
printer.handle_module(crate.root_module());
}
-void RustPrinter::print_attrs(const AST::MetaItems& attrs)
+void RustPrinter::print_attrs(const AST::AttributeList& attrs)
{
for(const auto& a : attrs.m_items)
{
@@ -829,6 +829,9 @@ void RustPrinter::print_bounds(const AST::GenericParams& params)
m_os << indent();
TU_MATCH(AST::GenericBound, (b), (ent),
+ (None,
+ m_os << "/*-*/";
+ ),
(Lifetime,
m_os << "'" << ent.test << ": '" << ent.bound;
),
@@ -836,10 +839,7 @@ void RustPrinter::print_bounds(const AST::GenericParams& params)
m_os << ent.type << ": '" << ent.bound;
),
(IsTrait,
- if( ent.hrls.size() > 0 ) {
- m_os << "for<'" << ::join(", '", ent.hrls) << "> ";
- }
- m_os << ent.type << ": " << ent.trait;
+ m_os << ent.outer_hrbs << ent.type << ": " << ent.inner_hrbs << ent.trait;
),
(MaybeTrait,
m_os << ent.type << ": ?" << ent.trait;
diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp
index 2c9a1c35..f3981db5 100644
--- a/src/ast/expr.hpp
+++ b/src/ast/expr.hpp
@@ -25,7 +25,7 @@ class NodeVisitor;
class ExprNode
{
- MetaItems m_attrs;
+ AttributeList m_attrs;
Span m_span;
public:
virtual ~ExprNode() = 0;
@@ -37,12 +37,10 @@ public:
void set_span(Span s) { m_span = ::std::move(s); }
const Span& span() const { return m_span; }
- void set_attrs(MetaItems&& mi) {
+ void set_attrs(AttributeList&& mi) {
m_attrs = mv$(mi);
}
- MetaItems& attrs() { return m_attrs; }
-
- static ::std::unique_ptr<ExprNode> from_deserialiser(Deserialiser& d);
+ AttributeList& attrs() { return m_attrs; }
};
typedef ::std::unique_ptr<ExprNode> ExprNodeP;
@@ -263,7 +261,7 @@ struct ExprNode_Loop:
struct ExprNode_Match_Arm
{
- MetaItems m_attrs;
+ AttributeList m_attrs;
::std::vector<Pattern> m_patterns;
unique_ptr<ExprNode> m_cond;
@@ -418,7 +416,7 @@ struct ExprNode_StructLiteral:
public ExprNode
{
struct Ent {
- MetaItems attrs;
+ AttributeList attrs;
::std::string name;
unique_ptr<ExprNode> value;
};
diff --git a/src/ast/generics.hpp b/src/ast/generics.hpp
index bc14202e..c222044c 100644
--- a/src/ast/generics.hpp
+++ b/src/ast/generics.hpp
@@ -14,49 +14,86 @@ namespace AST {
class TypeParam
{
+ ::AST::AttributeList m_attrs;
+ Span m_span;
+ // TODO: use an Ident?
::std::string m_name;
::TypeRef m_default;
public:
TypeParam(TypeParam&& x) = default;
TypeParam& operator=(TypeParam&& x) = default;
- TypeParam(const TypeParam& x):
- m_name(x.m_name),
- m_default(x.m_default.clone())
- {}
- //TypeParam(): m_name("") {}
- TypeParam(::std::string name):
+ explicit TypeParam(const TypeParam& x):
+ m_attrs( x.m_attrs ),
+ m_span( x.m_span ),
+ m_name( x.m_name ),
+ m_default( x.m_default.clone() )
+ {
+ }
+
+ TypeParam(Span sp, ::AST::AttributeList attrs, ::std::string name):
+ m_attrs( ::std::move(attrs) ),
+ m_span( ::std::move(sp) ),
m_name( ::std::move(name) ),
- m_default( Span() )
+ m_default(m_span)
{}
+
void setDefault(TypeRef type) {
assert(m_default.is_wildcard());
m_default = ::std::move(type);
}
- const ::std::string& name() const { return m_name; }
+ const ::AST::AttributeList& attrs() const { return m_attrs; }
+ const Span& span() const { return m_span; }
+ const ::std::string& name() const { return m_name; }
const TypeRef& get_default() const { return m_default; }
TypeRef& get_default() { return m_default; }
friend ::std::ostream& operator<<(::std::ostream& os, const TypeParam& tp);
};
+class LifetimeParam
+{
+ ::AST::AttributeList m_attrs;
+ Span m_span;
+ Ident m_name;
+public:
+ LifetimeParam(Span sp, ::AST::AttributeList attrs, Ident name):
+ m_attrs( ::std::move(attrs) ),
+ m_span( ::std::move(sp) ),
+ m_name( ::std::move(name) )
+ {
+ }
+ LifetimeParam(LifetimeParam&&) = default;
+ LifetimeParam& operator=(LifetimeParam&&) = default;
+ explicit LifetimeParam(const LifetimeParam&) = default;
+
+ const ::AST::AttributeList& attrs() const { return m_attrs; }
+ const Span& span() const { return m_span; }
+ const Ident& name() const { return m_name; }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const LifetimeParam& p);
+};
+
+// HigherRankedBounds is defined in `types.hpp`
-TAGGED_UNION_EX( GenericBound, (), Lifetime,
+TAGGED_UNION_EX( GenericBound, (), None,
(
+ (None, struct{}),
// Lifetime bound: 'test must be valid for 'bound
(Lifetime, struct {
- ::std::string test;
- ::std::string bound;
+ LifetimeRef test;
+ LifetimeRef bound;
}),
// Type lifetime bound
(TypeLifetime, struct {
TypeRef type;
- ::std::string bound;
+ LifetimeRef bound;
}),
// Standard trait bound: "Type: [for<'a>] Trait"
(IsTrait, struct {
+ HigherRankedBounds outer_hrbs;
TypeRef type;
- ::std::vector< ::std::string> hrls; // Higher-ranked lifetimes
+ HigherRankedBounds inner_hrbs;
AST::Path trait;
}),
// Removed trait bound: "Type: ?Trait"
@@ -84,9 +121,10 @@ TAGGED_UNION_EX( GenericBound, (), Lifetime,
GenericBound clone() const {
TU_MATCH(GenericBound, ( (*this) ), (ent),
+ (None, return make_None({}); ),
(Lifetime, return make_Lifetime({ent.test, ent.bound}); ),
(TypeLifetime, return make_TypeLifetime({ent.type.clone(), ent.bound}); ),
- (IsTrait, return make_IsTrait({ent.type.clone(), ent.hrls, ent.trait}); ),
+ (IsTrait, return make_IsTrait({ent.outer_hrbs, ent.type.clone(), ent.inner_hrbs, ent.trait}); ),
(MaybeTrait, return make_MaybeTrait({ent.type.clone(), ent.trait}); ),
(NotTrait, return make_NotTrait({ent.type.clone(), ent.trait}); ),
(Equality, return make_Equality({ent.type.clone(), ent.replacement.clone()}); )
@@ -101,7 +139,7 @@ TAGGED_UNION_EX( GenericBound, (), Lifetime,
class GenericParams
{
::std::vector<TypeParam> m_type_params;
- ::std::vector< ::std::string > m_lifetime_params;
+ ::std::vector<LifetimeParam> m_lifetime_params;
::std::vector<GenericBound> m_bounds;
public:
GenericParams() {}
@@ -112,7 +150,7 @@ public:
GenericParams clone() const {
GenericParams rv;
rv.m_type_params = ::std::vector<TypeParam>( m_type_params ); // Copy-constructable
- rv.m_lifetime_params = m_lifetime_params;
+ rv.m_lifetime_params = ::std::vector<LifetimeParam>(m_lifetime_params);
rv.m_bounds.reserve( m_bounds.size() );
for(auto& e: m_bounds)
rv.m_bounds.push_back( e.clone() );
@@ -121,12 +159,12 @@ public:
const ::std::vector<TypeParam>& ty_params() const { return m_type_params; }
::std::vector<TypeParam>& ty_params() { return m_type_params; }
- const ::std::vector< ::std::string>& lft_params() const { return m_lifetime_params; }
+ const ::std::vector<LifetimeParam>& lft_params() const { return m_lifetime_params; }
const ::std::vector<GenericBound>& bounds() const { return m_bounds; }
::std::vector<GenericBound>& bounds() { return m_bounds; }
void add_ty_param(TypeParam param) { m_type_params.push_back( ::std::move(param) ); }
- void add_lft_param(::std::string name) { m_lifetime_params.push_back( ::std::move(name) ); }
+ void add_lft_param(LifetimeParam lft) { m_lifetime_params.push_back( ::std::move(lft) ); }
void add_bound(GenericBound bound) {
m_bounds.push_back( ::std::move(bound) );
}
diff --git a/src/ast/item.hpp b/src/ast/item.hpp
index cc88f3e2..2137090d 100644
--- a/src/ast/item.hpp
+++ b/src/ast/item.hpp
@@ -2,7 +2,7 @@
#pragma once
#include <string>
-#include <serialise.hpp>
+#include <vector>
namespace AST {
@@ -25,10 +25,6 @@ struct NamedNS
is_pub( is_pub )
{
}
-
- //friend ::std::ostream& operator<<(::std::ostream& os, const Named& i) {
- // return os << (i.is_pub ? "pub " : " ") << i.name << ": " << i.data;
- //}
};
template <typename T>
diff --git a/src/ast/path.hpp b/src/ast/path.hpp
index 2126e3b2..0cb6fcc8 100644
--- a/src/ast/path.hpp
+++ b/src/ast/path.hpp
@@ -9,7 +9,6 @@
#include <vector>
#include <initializer_list>
#include <cassert>
-#include <serialise.hpp>
#include <tagged_union.hpp>
#include <string>
#include "../include/span.hpp"
@@ -28,6 +27,7 @@ class Static;
namespace AST {
+class LifetimeRef;
class GenericParams;
class Crate;
class Module;
@@ -109,14 +109,14 @@ extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding& x);
struct PathParams
{
- ::std::vector< ::std::string > m_lifetimes;
+ ::std::vector< LifetimeRef > m_lifetimes;
::std::vector< TypeRef > m_types;
::std::vector< ::std::pair< ::std::string, TypeRef> > m_assoc;
PathParams(PathParams&& x) = default;
PathParams(const PathParams& x);
PathParams() {}
- PathParams(::std::vector<::std::string> lfts, ::std::vector<TypeRef> tys, ::std::vector<::std::pair<::std::string,TypeRef>> a):
+ PathParams(::std::vector<LifetimeRef> lfts, ::std::vector<TypeRef> tys, ::std::vector<::std::pair<::std::string,TypeRef>> a):
m_lifetimes(mv$(lfts)),
m_types(mv$(tys)),
m_assoc(mv$(a))
diff --git a/src/ast/pattern.cpp b/src/ast/pattern.cpp
index 2a5ce0e5..72087d95 100644
--- a/src/ast/pattern.cpp
+++ b/src/ast/pattern.cpp
@@ -155,19 +155,6 @@ namespace AST {
)
return os;
}
-void operator%(Serialiser& s, Pattern::Value::Tag c) {
-}
-void operator%(::Deserialiser& s, Pattern::Value::Tag& c) {
-}
-void operator%(::Serialiser& s, const Pattern::Value& v) {
-}
-void operator%(::Deserialiser& s, Pattern::Value& v) {
-}
-
-void operator%(Serialiser& s, Pattern::Data::Tag c) {
-}
-void operator%(::Deserialiser& s, Pattern::Data::Tag& c) {
-}
Pattern::~Pattern()
{
@@ -252,10 +239,5 @@ AST::Pattern AST::Pattern::clone() const
return rv;
}
-#define _D(VAR, ...) case Pattern::Data::TAG_##VAR: { m_data = Pattern::Data::make_##VAR({}); auto& ent = m_data.as_##VAR(); (void)&ent; __VA_ARGS__ } break;
-SERIALISE_TYPE(Pattern::, "Pattern", {
-},{
-});
-
-}
+} // namespace AST
diff --git a/src/ast/pattern.hpp b/src/ast/pattern.hpp
index 583ce351..40cfa927 100644
--- a/src/ast/pattern.hpp
+++ b/src/ast/pattern.hpp
@@ -55,8 +55,7 @@ public:
bool is_valid() const { return m_name.name != ""; }
};
-class Pattern:
- public Serialisable
+class Pattern
{
public:
TAGGED_UNION(Value, Invalid,
@@ -106,40 +105,45 @@ public:
Pattern(Pattern&&) = default;
Pattern& operator=(Pattern&&) = default;
- Pattern(Data dat):
- m_binding(),
+ Pattern(Span sp, Data dat):
+ m_span( mv$(sp) ),
m_data( mv$(dat) )
{};
struct TagMaybeBind {};
- Pattern(TagMaybeBind, Ident name):
- m_binding(),
+ Pattern(TagMaybeBind, Span sp, Ident name):
+ m_span( mv$(sp) ),
m_data( Data::make_MaybeBind({ mv$(name) }) )
{}
struct TagMacro {};
- Pattern(TagMacro, unique_ptr<::AST::MacroInvocation> inv):
+ Pattern(TagMacro, Span sp, unique_ptr<::AST::MacroInvocation> inv):
+ m_span( mv$(sp) ),
m_data( Data::make_Macro({ mv$(inv) }) )
{}
struct TagBind {};
- Pattern(TagBind, Ident name, PatternBinding::Type ty = PatternBinding::Type::MOVE, bool is_mut=false):
+ Pattern(TagBind, Span sp, Ident name, PatternBinding::Type ty = PatternBinding::Type::MOVE, bool is_mut=false):
+ m_span( mv$(sp) ),
m_binding( PatternBinding(mv$(name), ty, is_mut) )
{}
struct TagBox {};
- Pattern(TagBox, Pattern sub):
+ Pattern(TagBox, Span sp, Pattern sub):
+ m_span( mv$(sp) ),
m_data( Data::make_Box({ unique_ptr<Pattern>(new Pattern(mv$(sub))) }) )
{}
struct TagValue {};
- Pattern(TagValue, Value val, Value end = Value()):
+ Pattern(TagValue, Span sp, Value val, Value end = Value()):
+ m_span( mv$(sp) ),
m_data( Data::make_Value({ ::std::move(val), ::std::move(end) }) )
{}
struct TagReference {};
- Pattern(TagReference, bool is_mutable, Pattern sub_pattern):
+ Pattern(TagReference, Span sp, bool is_mutable, Pattern sub_pattern):
+ m_span( mv$(sp) ),
m_data( Data::make_Ref( /*Data::Data_Ref */ {
is_mutable, unique_ptr<Pattern>(new Pattern(::std::move(sub_pattern)))
}) )
@@ -147,23 +151,28 @@ public:
}
struct TagTuple {};
- Pattern(TagTuple, ::std::vector<Pattern> pats):
+ Pattern(TagTuple, Span sp, ::std::vector<Pattern> pats):
+ m_span( mv$(sp) ),
m_data( Data::make_Tuple( TuplePat { mv$(pats), false, {} } ) )
{}
- Pattern(TagTuple, TuplePat pat):
+ Pattern(TagTuple, Span sp, TuplePat pat):
+ m_span( mv$(sp) ),
m_data( Data::make_Tuple( mv$(pat) ) )
{}
struct TagNamedTuple {};
- Pattern(TagNamedTuple, Path path, ::std::vector<Pattern> pats):
+ Pattern(TagNamedTuple, Span sp, Path path, ::std::vector<Pattern> pats):
+ m_span( mv$(sp) ),
m_data( Data::make_StructTuple( { mv$(path), TuplePat { mv$(pats), false, {} } } ) )
{}
- Pattern(TagNamedTuple, Path path, TuplePat pat = TuplePat { {}, false, {} }):
+ Pattern(TagNamedTuple, Span sp, Path path, TuplePat pat = TuplePat { {}, false, {} }):
+ m_span( mv$(sp) ),
m_data( Data::make_StructTuple( { ::std::move(path), ::std::move(pat) } ) )
{}
struct TagStruct {};
- Pattern(TagStruct, Path path, ::std::vector< ::std::pair< ::std::string,Pattern> > sub_patterns, bool is_exhaustive):
+ Pattern(TagStruct, Span sp, Path path, ::std::vector< ::std::pair< ::std::string,Pattern> > sub_patterns, bool is_exhaustive):
+ m_span( mv$(sp) ),
m_data( Data::make_Struct( { ::std::move(path), ::std::move(sub_patterns), is_exhaustive } ) )
{}
@@ -174,7 +183,6 @@ public:
const Span& span() const { return m_span; }
- void set_span(Span sp) { m_span = mv$(sp); }
Pattern clone() const;
@@ -187,13 +195,6 @@ public:
const Path& path() const { return m_data.as_StructTuple().path; }
friend ::std::ostream& operator<<(::std::ostream& os, const Pattern& pat);
-
- SERIALISABLE_PROTOTYPES();
- static ::std::unique_ptr<Pattern> from_deserialiser(Deserialiser& s) {
- ::std::unique_ptr<Pattern> ret(new Pattern);
- s.item(*ret);
- return ret;
- }
};
extern ::std::ostream& operator<<(::std::ostream& os, const Pattern::Value& val);
diff --git a/src/ast/types.cpp b/src/ast/types.cpp
index af99f3d7..98bc6ee1 100644
--- a/src/ast/types.cpp
+++ b/src/ast/types.cpp
@@ -128,7 +128,7 @@ TypeRef TypeRef::clone() const
_COPY(Primitive)
_COPY(Function)
_CLONE(Tuple, { H::clone_ty_vec(old.inner_types) })
- _CLONE(Borrow, { old.is_mut, box$(old.inner->clone()) })
+ _CLONE(Borrow, { AST::LifetimeRef(old.lifetime), old.is_mut, box$(old.inner->clone()) })
_CLONE(Pointer, { old.is_mut, box$(old.inner->clone()) })
_CLONE(Array, { box$(old.inner->clone()), old.size })
_COPY(Generic)
@@ -141,6 +141,15 @@ TypeRef TypeRef::clone() const
throw "";
}
+Ordering Type_TraitPath::ord(const Type_TraitPath& x) const
+{
+ Ordering rv;
+
+ rv = ::ord( this->path, x.path );
+ if(rv != OrdEqual) return rv;
+
+ return rv;
+}
Ordering TypeRef::ord(const TypeRef& x) const
{
Ordering rv;
@@ -277,7 +286,8 @@ void TypeRef::print(::std::ostream& os, bool is_debug/*=false*/) const
for( const auto& it : ent.traits ) {
if( &it != &ent.traits.front() )
os << "+";
- it.print_pretty(os, true, is_debug);
+ os << it.hrbs;
+ it.path.print_pretty(os, true, is_debug);
}
os << ")";
)
@@ -286,7 +296,8 @@ void TypeRef::print(::std::ostream& os, bool is_debug/*=false*/) const
for( const auto& it : ent.traits ) {
if( &it != &ent.traits.front() )
os << "+";
- it.print_pretty(os, true, is_debug);
+ os << it.hrbs;
+ it.path.print_pretty(os, true, is_debug);
}
os << "";
)
@@ -303,3 +314,21 @@ void TypeRef::print(::std::ostream& os, bool is_debug/*=false*/) const
return os;
}
+namespace AST {
+ ::std::ostream& operator<<(::std::ostream& os, const LifetimeRef& x) {
+ if( x.m_binding == LifetimeRef::BINDING_STATIC ) {
+ os << "'static";
+ }
+ else if( x.m_binding == LifetimeRef::BINDING_INFER ) {
+ os << "'_";
+ }
+ else {
+ os << "'" << x.m_name;
+ if( x.m_binding != LifetimeRef::BINDING_UNBOUND ) {
+ os << "/*" << x.m_binding << "*/";
+ }
+ }
+ return os;
+ }
+}
+
diff --git a/src/ast/types.hpp b/src/ast/types.hpp
index 820bcf27..b6d9d6f5 100644
--- a/src/ast/types.hpp
+++ b/src/ast/types.hpp
@@ -7,12 +7,70 @@
#include "coretypes.hpp"
#include "ast/path.hpp"
#include "ast/macro.hpp"
-#include <serialise.hpp>
#include <tagged_union.hpp>
namespace AST {
class ExprNode;
class Expr;
+class LifetimeParam;
+}
+
+namespace AST {
+
+ // Defined here for dependency reasons
+ class HigherRankedBounds
+ {
+ public:
+ ::std::vector<LifetimeParam> m_lifetimes;
+ //::std::vector<TypeParam> m_types;
+ //::std::vector<GenericBound> m_bounds;
+
+ bool empty() const {
+ return m_lifetimes.empty();
+ }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const HigherRankedBounds& x);
+ };
+
+ class LifetimeRef
+ {
+ static const uint16_t BINDING_STATIC = 0xFFFF;
+ static const uint16_t BINDING_UNBOUND = 0xFFFE;
+ static const uint16_t BINDING_INFER = 0xFFFD;
+
+ Ident m_name;
+ uint16_t m_binding;
+
+ LifetimeRef(Ident name, uint32_t binding):
+ m_name( ::std::move(name) ),
+ m_binding( binding )
+ {
+ }
+ public:
+ LifetimeRef():
+ LifetimeRef("", BINDING_INFER)
+ {
+ }
+ LifetimeRef(Ident name):
+ LifetimeRef(::std::move(name), BINDING_UNBOUND)
+ {
+ }
+ static LifetimeRef new_static() {
+ return LifetimeRef("static", BINDING_STATIC);
+ }
+
+ void set_binding(uint16_t b) { assert(m_binding == BINDING_UNBOUND); m_binding = b; }
+ bool is_unbound() const { return m_binding == BINDING_UNBOUND; }
+ bool is_infer() const { return m_binding == BINDING_INFER; }
+
+ const Ident& name() const { return m_name; }
+ Ordering ord(const LifetimeRef& x) const { return ::ord(m_name.name, x.m_name.name); }
+ bool operator==(const LifetimeRef& x) const { return ord(x) == OrdEqual; }
+ bool operator!=(const LifetimeRef& x) const { return ord(x) != OrdEqual; }
+ bool operator<(const LifetimeRef& x) const { return ord(x) == OrdLess; };
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const LifetimeRef& x);
+ };
}
class PrettyPrintType
@@ -37,6 +95,7 @@ struct TypeArgRef
struct Type_Function
{
+ AST::HigherRankedBounds hrbs;
bool is_unsafe;
::std::string m_abi;
::std::unique_ptr<TypeRef> m_rettype;
@@ -44,7 +103,8 @@ struct Type_Function
bool is_variadic;
Type_Function() {}
- Type_Function(bool is_unsafe, ::std::string abi, ::std::unique_ptr<TypeRef> ret, ::std::vector<TypeRef> args, bool is_variadic):
+ Type_Function(AST::HigherRankedBounds hrbs, bool is_unsafe, ::std::string abi, ::std::unique_ptr<TypeRef> ret, ::std::vector<TypeRef> args, bool is_variadic):
+ hrbs(mv$(hrbs)),
is_unsafe(is_unsafe),
m_abi(mv$(abi)),
m_rettype(mv$(ret)),
@@ -57,6 +117,14 @@ struct Type_Function
Ordering ord(const Type_Function& x) const;
};
+struct Type_TraitPath
+{
+ AST::HigherRankedBounds hrbs;
+ AST::Path path;
+
+ Ordering ord(const Type_TraitPath& x) const;
+};
+
TAGGED_UNION(TypeData, None,
(None, struct { }),
(Any, struct { }),
@@ -75,6 +143,7 @@ TAGGED_UNION(TypeData, None,
::std::vector<TypeRef> inner_types;
}),
(Borrow, struct {
+ AST::LifetimeRef lifetime;
bool is_mut;
::std::unique_ptr<TypeRef> inner;
}),
@@ -94,12 +163,12 @@ TAGGED_UNION(TypeData, None,
AST::Path path;
}),
(TraitObject, struct {
- ::std::vector<::std::string> hrls;
- ::std::vector<AST::Path> traits;
+ ::std::vector<Type_TraitPath> traits;
+ ::std::vector<AST::LifetimeRef> lifetimes;
}),
(ErasedType, struct {
- ::std::vector<::std::string> hrls;
- ::std::vector<AST::Path> traits;
+ ::std::vector<Type_TraitPath> traits;
+ ::std::vector<AST::LifetimeRef> lifetimes;
})
);
@@ -171,15 +240,15 @@ public:
m_data(TypeData::make_Tuple({::std::move(inner_types)}))
{}
struct TagFunction {};
- TypeRef(TagFunction, Span sp, bool is_unsafe, ::std::string abi, ::std::vector<TypeRef> args, bool is_variadic, TypeRef ret):
+ TypeRef(TagFunction, Span sp, AST::HigherRankedBounds hrbs, bool is_unsafe, ::std::string abi, ::std::vector<TypeRef> args, bool is_variadic, TypeRef ret):
m_span(mv$(sp)),
- m_data(TypeData::make_Function({ Type_Function( is_unsafe, abi, box$(ret), mv$(args), is_variadic ) }))
+ m_data(TypeData::make_Function({ Type_Function( mv$(hrbs), is_unsafe, abi, box$(ret), mv$(args), is_variadic ) }))
{}
struct TagReference {};
- TypeRef(TagReference , Span sp, bool is_mut, TypeRef inner_type):
+ TypeRef(TagReference , Span sp, AST::LifetimeRef lft, bool is_mut, TypeRef inner_type):
m_span(mv$(sp)),
- m_data(TypeData::make_Borrow({ is_mut, ::make_unique_ptr(mv$(inner_type)) }))
+ m_data(TypeData::make_Borrow({ ::std::move(lft), is_mut, ::make_unique_ptr(mv$(inner_type)) }))
{}
struct TagPointer {};
TypeRef(TagPointer , Span sp, bool is_mut, TypeRef inner_type):
@@ -215,9 +284,9 @@ public:
TypeRef(TagPath(), mv$(sp), mv$(path))
{}
- TypeRef( Span sp, ::std::vector<::std::string> hrls, ::std::vector<AST::Path> traits ):
+ TypeRef( Span sp, ::std::vector<Type_TraitPath> traits, ::std::vector<AST::LifetimeRef> lifetimes ):
m_span(mv$(sp)),
- m_data(TypeData::make_TraitObject({ mv$(hrls), ::std::move(traits) }))
+ m_data(TypeData::make_TraitObject({ ::std::move(traits), mv$(lifetimes) }))
{}
diff --git a/src/expand/cfg.cpp b/src/expand/cfg.cpp
index a2fca312..773a38c4 100644
--- a/src/expand/cfg.cpp
+++ b/src/expand/cfg.cpp
@@ -30,7 +30,7 @@ void Cfg_SetValueCb(::std::string name, ::std::function<bool(const ::std::string
g_cfg_value_fcns.insert( ::std::make_pair(mv$(name), mv$(cb)) );
}
-bool check_cfg(Span sp, const ::AST::MetaItem& mi) {
+bool check_cfg(const Span& sp, const ::AST::Attribute& mi) {
if( mi.has_sub_items() ) {
// Must be `any`/`not`/`all`
@@ -117,7 +117,7 @@ class CCfgHandler:
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
DEBUG("#[cfg] crate - " << mi);
// Ignore, as #[cfg] on a crate is handled in expand/mod.cpp
if( check_cfg(sp, mi) ) {
@@ -126,7 +126,7 @@ class CCfgHandler:
crate.m_root_module.items().clear();
}
}
- void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
TRACE_FUNCTION_FR("#[cfg] item - " << mi, (i.is_None() ? "Deleted" : ""));
if( check_cfg(sp, mi) ) {
// Leave
@@ -135,7 +135,7 @@ class CCfgHandler:
i = AST::Item::make_None({});
}
}
- void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, ::std::unique_ptr<AST::ExprNode>& expr) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, ::std::unique_ptr<AST::ExprNode>& expr) const override {
DEBUG("#[cfg] expr - " << mi);
if( check_cfg(sp, mi) ) {
// Leave
@@ -144,7 +144,7 @@ class CCfgHandler:
expr.reset();
}
}
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const override {
DEBUG("#[cfg] impl - " << mi);
if( check_cfg(sp, mi) ) {
// Leave
@@ -154,32 +154,32 @@ class CCfgHandler:
}
}
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::StructItem& si) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::AST::StructItem& si) const override {
DEBUG("#[cfg] struct item - " << mi);
if( !check_cfg(sp, mi) ) {
si.m_name = "";
}
}
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::TupleItem& i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::AST::TupleItem& i) const override {
DEBUG("#[cfg] tuple item - " << mi);
if( !check_cfg(sp, mi) ) {
i.m_type = ::TypeRef(sp);
}
}
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::EnumVariant& i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::AST::EnumVariant& i) const override {
DEBUG("#[cfg] enum variant - " << mi);
if( !check_cfg(sp, mi) ) {
i.m_name = "";
}
}
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::ExprNode_Match_Arm& i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::AST::ExprNode_Match_Arm& i) const override {
DEBUG("#[cfg] match arm - " << mi);
if( !check_cfg(sp, mi) ) {
i.m_patterns.clear();
}
}
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::ExprNode_StructLiteral::Ent& i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::AST::ExprNode_StructLiteral::Ent& i) const override {
DEBUG("#[cfg] struct lit - " << mi);
if( !check_cfg(sp, mi) ) {
i.value.reset();
diff --git a/src/expand/cfg.hpp b/src/expand/cfg.hpp
index edf17851..7c7785bb 100644
--- a/src/expand/cfg.hpp
+++ b/src/expand/cfg.hpp
@@ -6,4 +6,4 @@
extern void Cfg_SetFlag(::std::string name);
extern void Cfg_SetValue(::std::string name, ::std::string val);
extern void Cfg_SetValueCb(::std::string name, ::std::function<bool(const ::std::string&)> cb);
-extern bool check_cfg(Span sp, const ::AST::MetaItem& mi);
+extern bool check_cfg(const Span& sp, const ::AST::Attribute& mi);
diff --git a/src/expand/crate_tags.cpp b/src/expand/crate_tags.cpp
index e99f1aa2..0e7d8447 100644
--- a/src/expand/crate_tags.cpp
+++ b/src/expand/crate_tags.cpp
@@ -14,7 +14,7 @@ class Decorator_CrateType:
public:
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
if( crate.m_crate_type != AST::Crate::Type::Unknown ) {
//ERROR(sp, E0000, "Multiple #![crate_type] attributes");
return ;
@@ -41,7 +41,7 @@ class Decorator_CrateName:
public:
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
if( crate.m_crate_name != "" ) {
ERROR(sp, E0000, "Multiple #![crate_name] attributes");
}
@@ -58,7 +58,7 @@ class Decorator_Allocator:
public:
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
// TODO: Check for an existing allocator crate
crate.m_lang_items.insert(::std::make_pair( "mrustc-allocator", AST::Path("",{}) ));
}
@@ -69,7 +69,7 @@ class Decorator_PanicRuntime:
public:
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
// TODO: Check for an existing panic_runtime crate
crate.m_lang_items.insert(::std::make_pair( "mrustc-panic_runtime", AST::Path("",{}) ));
}
@@ -80,7 +80,7 @@ class Decorator_NeedsPanicRuntime:
public:
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
crate.m_lang_items.insert(::std::make_pair( "mrustc-needs_panic_runtime", AST::Path("",{}) ));
}
};
diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp
index 3b25831c..f7c8fabc 100644
--- a/src/expand/derive.cpp
+++ b/src/expand/derive.cpp
@@ -86,7 +86,7 @@ struct Deriver
for(const auto& arg : params.ty_params())
{
params.add_bound( ::AST::GenericBound::make_IsTrait({
- TypeRef(sp, arg.name(), i), {}, trait_path
+ {}, TypeRef(sp, arg.name(), i), {}, trait_path
}) );
i ++;
}
@@ -96,7 +96,7 @@ struct Deriver
for(auto& ty : additional_bounded_types)
{
params.add_bound( ::AST::GenericBound::make_IsTrait({
- mv$(ty), {}, trait_path
+ {}, mv$(ty), {}, trait_path
}) );
}
@@ -285,7 +285,7 @@ class Deriver_Debug:
AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path debug_trait = AST::Path(core_name, { AST::PathNode("fmt", {}), AST::PathNode("Debug", {}) });
- TypeRef f_type(TypeRef::TagReference(), sp, true,
+ TypeRef f_type(TypeRef::TagReference(), sp, AST::LifetimeRef(), true,
TypeRef(sp, AST::Path(core_name, {AST::PathNode("fmt",{}), AST::PathNode("Formatter", {})}))
);
@@ -295,15 +295,15 @@ class Deriver_Debug:
ABI_RUST, false, false, false,
TypeRef(sp, AST::Path(core_name, {AST::PathNode("fmt",{}), AST::PathNode("Result",{})}) ),
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) ),
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "f"), mv$(f_type) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ),
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "f"), mv$(f_type) )
)
);
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
AST::GenericParams params = get_params_with_bounds(sp, p, debug_trait, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, debug_trait), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, debug_trait), type.clone() ) );
rv.add_function(false, false, "fmt", mv$(fcn));
return mv$(rv);
}
@@ -392,7 +392,7 @@ public:
AST::PathNode("write_str",{}),
vec$( NEWNODE(String, v.m_name) )
);
- pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
@@ -407,7 +407,7 @@ public:
for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
{
auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) );
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
node = NEWNODE(CallMethod,
mv$(node), AST::PathNode("field",{}),
@@ -418,7 +418,7 @@ public:
}
code = NEWNODE(CallMethod, mv$(node), AST::PathNode("finish",{}), {});
- pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a));
+ pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
),
(Struct,
::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
@@ -433,7 +433,7 @@ public:
for( const auto& fld : e.m_fields )
{
auto name_a = FMT("a" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) );
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
node = NEWNODE(CallMethod,
mv$(node), AST::PathNode("field",{}),
@@ -445,12 +445,12 @@ public:
}
code = NEWNODE(CallMethod, mv$(node), AST::PathNode("finish",{}), {});
- pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true);
+ pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
)
)
::std::vector< AST::Pattern> pats;
- pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
arms.push_back(AST::ExprNode_Match_Arm(
mv$(pats),
@@ -480,15 +480,15 @@ class Deriver_PartialEq:
ABI_RUST, false, false, false,
TypeRef(sp, CORETYPE_BOOL),
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) ),
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "v" ), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ),
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "v" ), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) )
)
);
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
rv.add_function(false, false, "eq", mv$(fcn));
return mv$(rv);
}
@@ -550,8 +550,8 @@ public:
TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
(Value,
code = NEWNODE(Bool, true);
- pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
- pat_b = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_b = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
@@ -562,8 +562,8 @@ public:
{
auto name_a = FMT("a" << idx);
auto name_b = FMT("b" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) );
- pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF) );
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
+ pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
nodes.push_back(this->compare_and_ret(sp, core_name,
NEWNODE(NamedValue, AST::Path(name_a)),
NEWNODE(NamedValue, AST::Path(name_b))
@@ -571,8 +571,8 @@ public:
}
nodes.push_back( NEWNODE(Bool, true) );
- pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a));
- pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_b));
+ pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
+ pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
@@ -584,8 +584,8 @@ public:
{
auto name_a = FMT("a" << fld.m_name);
auto name_b = FMT("b" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) );
- pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF)) );
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
+ pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
nodes.push_back(this->compare_and_ret(sp, core_name,
NEWNODE(NamedValue, AST::Path(name_a)),
NEWNODE(NamedValue, AST::Path(name_b))
@@ -593,8 +593,8 @@ public:
}
nodes.push_back( NEWNODE(Bool, true) );
- pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true);
- pat_b = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_b), true);
+ pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
+ pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true);
code = NEWNODE(Block, mv$(nodes));
)
)
@@ -602,9 +602,9 @@ public:
::std::vector< AST::Pattern> pats;
{
::std::vector< AST::Pattern> tuple_pats;
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) );
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) );
- pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) );
+ tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
+ tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) );
}
arms.push_back(AST::ExprNode_Match_Arm(
@@ -659,15 +659,15 @@ class Deriver_PartialOrd:
ABI_RUST, false, false, false,
TypeRef(sp, path_option_ordering),
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) ),
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "v" ), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ),
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "v" ), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) )
)
);
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
rv.add_function(false, false, "partial_cmp", mv$(fcn));
return mv$(rv);
}
@@ -683,19 +683,19 @@ class Deriver_PartialOrd:
),
::make_vec3(
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), this->get_path(core_name, "option", "Option", "None")) ),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "option", "Option", "None")) ),
nullptr,
NEWNODE(Flow, AST::ExprNode_Flow::RETURN, "", NEWNODE(NamedValue, this->get_path(core_name, "option", "Option", "None")))
),
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagNamedTuple(), this->get_path(core_name, "option", "Option", "Some"),
- ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), this->get_path(core_name, "cmp", "Ordering", "Equal")) )
+ ::make_vec1( AST::Pattern(AST::Pattern::TagNamedTuple(), sp, this->get_path(core_name, "option", "Option", "Some"),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "cmp", "Ordering", "Equal")) )
) ),
nullptr,
NEWNODE(Tuple, ::std::vector<AST::ExprNodeP>())
),
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagBind(), "res") ),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagBind(), sp, "res") ),
nullptr,
NEWNODE(Flow, AST::ExprNode_Flow::RETURN, "", NEWNODE(NamedValue, AST::Path("res")))
)
@@ -758,8 +758,8 @@ public:
TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
(Value,
code = this->make_ret_equal(core_name);
- pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
- pat_b = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_b = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
@@ -770,8 +770,8 @@ public:
{
auto name_a = FMT("a" << idx);
auto name_b = FMT("b" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) );
- pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF) );
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
+ pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
nodes.push_back(this->make_compare_and_ret( sp, core_name,
NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_a))),
@@ -780,8 +780,8 @@ public:
}
nodes.push_back( this->make_ret_equal(core_name) );
- pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a));
- pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_b));
+ pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
+ pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
@@ -793,8 +793,8 @@ public:
{
auto name_a = FMT("a" << fld.m_name);
auto name_b = FMT("b" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) );
- pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF)) );
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
+ pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
nodes.push_back(this->make_compare_and_ret( sp, core_name,
NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_a))),
@@ -803,8 +803,8 @@ public:
}
nodes.push_back( this->make_ret_equal(core_name) );
- pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true);
- pat_b = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_b), true);
+ pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
+ pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true);
code = NEWNODE(Block, mv$(nodes));
)
)
@@ -812,9 +812,9 @@ public:
::std::vector< AST::Pattern> pats;
{
::std::vector< AST::Pattern> tuple_pats;
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) );
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) );
- pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) );
+ tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
+ tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) );
}
arms.push_back(AST::ExprNode_Match_Arm(
@@ -834,32 +834,32 @@ public:
continue ;
struct H {
- static ::AST::Pattern get_pat_nc(const AST::Path& base_path, const AST::EnumVariant& v) {
+ static ::AST::Pattern get_pat_nc(const Span& sp, const AST::Path& base_path, const AST::EnumVariant& v) {
AST::Path var_path = base_path + v.m_name;
TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
(Value,
- return AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(var_path));
+ return AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(var_path));
),
(Tuple,
- return AST::Pattern(AST::Pattern::TagNamedTuple(), var_path, AST::Pattern::TuplePat { {}, true, {} });
+ return AST::Pattern(AST::Pattern::TagNamedTuple(), sp, var_path, AST::Pattern::TuplePat { {}, true, {} });
),
(Struct,
- return AST::Pattern(AST::Pattern::TagStruct(), var_path, {}, false);
+ return AST::Pattern(AST::Pattern::TagStruct(), sp, var_path, {}, false);
)
)
throw "";
}
};
- ::AST::Pattern pat_a = H::get_pat_nc(base_path, enm.variants()[a]);
- ::AST::Pattern pat_b = H::get_pat_nc(base_path, enm.variants()[b]);
+ ::AST::Pattern pat_a = H::get_pat_nc(sp, base_path, enm.variants()[a]);
+ ::AST::Pattern pat_b = H::get_pat_nc(sp, base_path, enm.variants()[b]);
::std::vector< AST::Pattern> pats;
{
::std::vector< AST::Pattern> tuple_pats;
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) );
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) );
- pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) );
+ tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
+ tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) );
}
auto code = NEWNODE(CallPath, this->get_path(core_name, "option", "Option", "Some"),
@@ -903,14 +903,14 @@ class Deriver_Eq:
ABI_RUST, false, false, false,
TypeRef(TypeRef::TagUnit(), sp),
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) )
)
);
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
rv.add_function(false, false, "assert_receiver_is_total_eq", mv$(fcn));
return mv$(rv);
}
@@ -968,7 +968,7 @@ public:
TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
(Value,
code = NEWNODE(Block);
- pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
@@ -977,11 +977,11 @@ public:
for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
{
auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) );
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) );
}
- pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a));
+ pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
@@ -991,17 +991,17 @@ public:
for( const auto& fld : e.m_fields )
{
auto name_a = FMT("a" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) );
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) );
}
- pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true);
+ pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
code = NEWNODE(Block, mv$(nodes));
)
)
::std::vector< AST::Pattern> pats;
- pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
arms.push_back(AST::ExprNode_Match_Arm(
mv$(pats),
@@ -1054,15 +1054,15 @@ class Deriver_Ord:
ABI_RUST, false, false, false,
TypeRef(sp, path_ordering),
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) ),
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "v"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ),
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "v"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) )
)
);
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
rv.add_function(false, false, "cmp", mv$(fcn));
return mv$(rv);
}
@@ -1079,12 +1079,12 @@ class Deriver_Ord:
),
::make_vec2(
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), this->get_path(core_name, "cmp", "Ordering", "Equal")) ),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "cmp", "Ordering", "Equal")) ),
nullptr,
NEWNODE(Tuple, ::std::vector<AST::ExprNodeP>())
),
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagBind(), "res") ),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagBind(), sp, "res") ),
nullptr,
NEWNODE(Flow, AST::ExprNode_Flow::RETURN, "", NEWNODE(NamedValue, AST::Path("res")))
)
@@ -1145,8 +1145,8 @@ public:
TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
(Value,
code = this->make_ret_equal(core_name);
- pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
- pat_b = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_b = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
@@ -1157,8 +1157,8 @@ public:
{
auto name_a = FMT("a" << idx);
auto name_b = FMT("b" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) );
- pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF) );
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
+ pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
nodes.push_back(this->make_compare_and_ret( sp, core_name,
NEWNODE(NamedValue, AST::Path(name_a)),
@@ -1167,8 +1167,8 @@ public:
}
nodes.push_back( this->make_ret_equal(core_name) );
- pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a));
- pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_b));
+ pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
+ pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
@@ -1180,8 +1180,8 @@ public:
{
auto name_a = FMT("a" << fld.m_name);
auto name_b = FMT("b" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) );
- pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF)) );
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
+ pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
nodes.push_back(this->make_compare_and_ret( sp, core_name,
NEWNODE(NamedValue, AST::Path(name_a)),
@@ -1190,8 +1190,8 @@ public:
}
nodes.push_back( this->make_ret_equal(core_name) );
- pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true);
- pat_b = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_b), true);
+ pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
+ pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true);
code = NEWNODE(Block, mv$(nodes));
)
)
@@ -1199,9 +1199,9 @@ public:
::std::vector< AST::Pattern> pats;
{
::std::vector< AST::Pattern> tuple_pats;
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) );
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) );
- pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) );
+ tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
+ tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) );
}
arms.push_back(AST::ExprNode_Match_Arm(
@@ -1219,32 +1219,32 @@ public:
continue ;
struct H {
- static ::AST::Pattern get_pat_nc(const AST::Path& base_path, const AST::EnumVariant& v) {
+ static ::AST::Pattern get_pat_nc(const Span& sp, const AST::Path& base_path, const AST::EnumVariant& v) {
AST::Path var_path = base_path + v.m_name;
TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
(Value,
- return AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(var_path));
+ return AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(var_path));
),
(Tuple,
- return AST::Pattern(AST::Pattern::TagNamedTuple(), var_path, AST::Pattern::TuplePat { {}, true, {} });
+ return AST::Pattern(AST::Pattern::TagNamedTuple(), sp, var_path, AST::Pattern::TuplePat { {}, true, {} });
),
(Struct,
- return AST::Pattern(AST::Pattern::TagStruct(), var_path, {}, false);
+ return AST::Pattern(AST::Pattern::TagStruct(), sp, var_path, {}, false);
)
)
throw "";
}
};
- ::AST::Pattern pat_a = H::get_pat_nc(base_path, enm.variants()[a]);
- ::AST::Pattern pat_b = H::get_pat_nc(base_path, enm.variants()[b]);
+ ::AST::Pattern pat_a = H::get_pat_nc(sp, base_path, enm.variants()[a]);
+ ::AST::Pattern pat_b = H::get_pat_nc(sp, base_path, enm.variants()[b]);
::std::vector< AST::Pattern> pats;
{
::std::vector< AST::Pattern> tuple_pats;
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) );
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) );
- pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) );
+ tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
+ tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) );
}
auto code = NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", (a < b ? "Less" : "Greater")));
@@ -1287,14 +1287,14 @@ class Deriver_Clone:
ABI_RUST, false, false, false,
TypeRef(sp, "Self", 0xFFFF),
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) )
)
);
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
rv.add_function(false, false, "clone", mv$(fcn));
return mv$(rv);
}
@@ -1361,7 +1361,7 @@ public:
TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
(Value,
code = NEWNODE(NamedValue, base_path + v.m_name);
- pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
@@ -1370,11 +1370,11 @@ public:
for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
{
auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) );
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
nodes.push_back( this->clone_val_direct(core_name, NEWNODE(NamedValue, AST::Path(name_a))) );
}
- pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a));
+ pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
code = NEWNODE(CallPath, base_path + v.m_name, mv$(nodes));
),
(Struct,
@@ -1384,17 +1384,17 @@ public:
for( const auto& fld : e.m_fields )
{
auto name_a = FMT("a" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) );
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
vals.push_back({ {}, fld.m_name, this->clone_val_direct(core_name, NEWNODE(NamedValue, AST::Path(name_a))) });
}
- pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true);
+ pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
code = NEWNODE(StructLiteral, base_path + v.m_name, nullptr, mv$(vals));
)
)
::std::vector< AST::Pattern> pats;
- pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
arms.push_back(AST::ExprNode_Match_Arm(
mv$(pats),
@@ -1439,7 +1439,7 @@ class Deriver_Copy:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
return mv$(rv);
}
@@ -1486,7 +1486,7 @@ class Deriver_Default:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
rv.add_function(false, false, "default", mv$(fcn));
return mv$(rv);
}
@@ -1559,21 +1559,20 @@ class Deriver_Hash:
ABI_RUST, false, false, false,
TypeRef(TypeRef::TagUnit(), sp),
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) ),
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "state"), TypeRef(TypeRef::TagReference(), sp, true, TypeRef(sp, "H", 0x100|0)) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ),
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "state"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, TypeRef(sp, "H", 0x100|0)) )
)
);
- fcn.params().add_ty_param( AST::TypeParam("H") );
+ fcn.params().add_ty_param( AST::TypeParam(sp, {}, "H") );
fcn.params().add_bound( AST::GenericBound::make_IsTrait({
- TypeRef(sp, "H", 0x100|0),
- {},
- this->get_trait_path_Hasher(core_name)
+ {}, TypeRef(sp, "H", 0x100|0),
+ {}, this->get_trait_path_Hasher(core_name)
}) );
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
rv.add_function(false, false, "hash", mv$(fcn));
return mv$(rv);
}
@@ -1634,7 +1633,7 @@ public:
TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
(Value,
code = mv$(var_idx_hash);
- pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
@@ -1644,11 +1643,11 @@ public:
for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
{
auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) );
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
nodes.push_back( this->hash_val_direct(core_name, NEWNODE(NamedValue, AST::Path(name_a))) );
}
- pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a));
+ pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
@@ -1659,17 +1658,17 @@ public:
for( const auto& fld : e.m_fields )
{
auto name_a = FMT("a" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) );
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
nodes.push_back( this->hash_val_direct(core_name, NEWNODE(NamedValue, AST::Path(name_a))) );
}
- pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true);
+ pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
code = NEWNODE(Block, mv$(nodes));
)
)
::std::vector< AST::Pattern> pats;
- pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
arms.push_back(AST::ExprNode_Match_Arm(
mv$(pats),
@@ -1713,21 +1712,20 @@ class Deriver_RustcEncodable:
ABI_RUST, false, false, false,
TypeRef(sp, mv$(result_path)),
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) ),
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "s"), TypeRef(TypeRef::TagReference(), sp, true, TypeRef(sp, "S", 0x100|0)) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ),
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "s"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, TypeRef(sp, "S", 0x100|0)) )
)
);
- fcn.params().add_ty_param( AST::TypeParam("S") );
+ fcn.params().add_ty_param( AST::TypeParam(sp, {}, "S") );
fcn.params().add_bound( AST::GenericBound::make_IsTrait({
- TypeRef(sp, "S", 0x100|0),
- {},
- this->get_trait_path_Encoder()
+ {}, TypeRef(sp, "S", 0x100|0),
+ {}, this->get_trait_path_Encoder()
}) );
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
rv.add_function(false, false, "encode", mv$(fcn));
return mv$(rv);
}
@@ -1743,7 +1741,7 @@ class Deriver_RustcEncodable:
AST::ExprNodeP enc_closure(Span sp, AST::ExprNodeP code) const {
return NEWNODE(Closure,
- vec$( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "s"), ::TypeRef(sp) ) ), ::TypeRef(sp),
+ vec$( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "s"), ::TypeRef(sp) ) ), ::TypeRef(sp),
mv$(code), false
);
}
@@ -1832,7 +1830,7 @@ public:
this->enc_closure(sp, this->get_val_ok(core_name))
)
);
- pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name));
+ pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
@@ -1841,7 +1839,7 @@ public:
for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
{
auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) );
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant_arg",
vec$(
NEWNODE(NamedValue, AST::Path("s")),
@@ -1861,7 +1859,7 @@ public:
this->enc_closure(sp, NEWNODE(Block, mv$(nodes)))
)
);
- pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a));
+ pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
),
(Struct,
::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
@@ -1871,7 +1869,7 @@ public:
for( const auto& fld : e.m_fields )
{
auto name_a = Ident( FMT("a" << fld.m_name) );
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), Ident(name_a), ::AST::PatternBinding::Type::REF)) );
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, Ident(name_a), ::AST::PatternBinding::Type::REF)) );
nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant_field",
vec$(
@@ -1885,7 +1883,7 @@ public:
}
nodes.push_back( this->get_val_ok(core_name) );
- pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true);
+ pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant",
vec$(
NEWNODE(NamedValue, AST::Path("s")),
@@ -1899,7 +1897,7 @@ public:
)
::std::vector< AST::Pattern> pats;
- pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
arms.push_back(AST::ExprNode_Match_Arm(
mv$(pats),
@@ -1947,21 +1945,20 @@ class Deriver_RustcDecodable:
ABI_RUST, false, false, false,
TypeRef(sp, result_path),
vec$(
- //::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef(sp, "Self", 0xFFFF)) ),
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "d"), TypeRef(TypeRef::TagReference(), sp, true, TypeRef(sp, "D", 0x100|0)) )
+ //::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, false, AST::LifetimeRef(), TypeRef(sp, "Self", 0xFFFF)) ),
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "d"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, TypeRef(sp, "D", 0x100|0)) )
)
);
- fcn.params().add_ty_param( AST::TypeParam("D") );
+ fcn.params().add_ty_param( AST::TypeParam(sp, {}, "D") );
fcn.params().add_bound( AST::GenericBound::make_IsTrait({
- TypeRef(sp, "D", 0x100|0),
- {},
- this->get_trait_path_Decoder()
+ {}, TypeRef(sp, "D", 0x100|0),
+ {}, this->get_trait_path_Decoder()
}) );
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
- AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
+ AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
rv.add_function(false, false, "decode", mv$(fcn));
return mv$(rv);
}
@@ -1974,7 +1971,7 @@ class Deriver_RustcDecodable:
AST::ExprNodeP dec_closure(Span sp, AST::ExprNodeP code) const {
return NEWNODE(Closure,
- vec$( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "d"), ::TypeRef(sp) ) ), ::TypeRef(sp),
+ vec$( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "d"), ::TypeRef(sp) ) ), ::TypeRef(sp),
mv$(code), false
);
}
@@ -2115,7 +2112,7 @@ public:
)
::std::vector< AST::Pattern> pats;
- pats.push_back( AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Integer({CORETYPE_UINT, var_idx})) );
+ pats.push_back( AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Integer({CORETYPE_UINT, var_idx})) );
arms.push_back(AST::ExprNode_Match_Arm(
mv$(pats),
@@ -2137,8 +2134,8 @@ public:
auto node_match = NEWNODE(Match, NEWNODE(NamedValue, AST::Path("idx")), mv$(arms));
auto node_var_closure = NEWNODE(Closure,
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "d"), ::TypeRef(sp) ),
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "idx"), ::TypeRef(sp) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "d"), ::TypeRef(sp) ),
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "idx"), ::TypeRef(sp) )
),
::TypeRef(sp),
mv$(node_match),
@@ -2185,7 +2182,7 @@ static const Deriver* find_impl(const ::std::string& trait_name)
}
template<typename T>
-static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mod, const AST::MetaItem& attr, const AST::Path& path, const T& item)
+static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mod, const AST::Attribute& attr, const AST::Path& path, const T& item)
{
if( !attr.has_sub_items() ) {
//ERROR(sp, E0000, "#[derive()] requires a list of known traits to derive");
@@ -2257,7 +2254,7 @@ class Decorator_Derive:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::MetaItem& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
{
TU_MATCH_DEF(::AST::Item, (i), (e),
(
diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp
index 53606bea..789ad88e 100644
--- a/src/expand/lang_item.cpp
+++ b/src/expand/lang_item.cpp
@@ -125,7 +125,7 @@ class Decorator_LangItem:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::MetaItem& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
{
TU_MATCH_DEF(::AST::Item, (i), (e),
(
@@ -154,7 +154,7 @@ public:
)
}
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const override {
const ::std::string& name = mi.string();
if( name == "i8" ) {}
@@ -193,7 +193,7 @@ class Decorator_Main:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::MetaItem& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
{
if( i.is_None() ) {
// Ignore.
@@ -217,7 +217,7 @@ class Decorator_Start:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::MetaItem& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
{
TU_IFLET(::AST::Item, i, Function, e,
auto rv = crate.m_lang_items.insert(::std::make_pair( ::std::string("mrustc-start"), ::AST::Path(path) ));
diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp
index 5b783949..5aa15a46 100644
--- a/src/expand/macro_rules.cpp
+++ b/src/expand/macro_rules.cpp
@@ -41,7 +41,7 @@ class CMacroUseHandler:
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
{
TRACE_FUNCTION_F("path=" << path);
@@ -120,7 +120,7 @@ class CMacroExportHandler:
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
{
if( i.is_None() ) {
}
@@ -147,7 +147,7 @@ class CMacroReexportHandler:
public ExpandDecorator
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
{
if( !i.is_Crate() ) {
ERROR(sp, E0000, "Use of #[macro_reexport] on non-crate - " << i.tag_str());
diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp
index 571d21e2..8e052dfe 100644
--- a/src/expand/mod.cpp
+++ b/src/expand/mod.cpp
@@ -21,7 +21,7 @@ MacroDef* g_macros_list = nullptr;
::std::map< ::std::string, ::std::unique_ptr<ExpandDecorator> > g_decorators;
::std::map< ::std::string, ::std::unique_ptr<ExpandProcMacro> > g_macros;
-void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::std::function<void(const ExpandDecorator& d,const ::AST::MetaItem& a)> f);
+void Expand_Attrs(const ::AST::AttributeList& attrs, AttrStage stage, ::std::function<void(const ExpandDecorator& d,const ::AST::Attribute& a)> f);
void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Path modpath, ::AST::Module& mod, unsigned int first_item = 0);
void Expand_Expr(::AST::Crate& crate, LList<const AST::Module*> modstack, AST::Expr& node);
void Expand_Expr(::AST::Crate& crate, LList<const AST::Module*> modstack, ::std::shared_ptr<AST::ExprNode>& node);
@@ -43,12 +43,12 @@ void Register_Synext_Macro_Static(MacroDef* def) {
}
-void ExpandDecorator::unexpected(const Span& sp, const AST::MetaItem& mi, const char* loc_str) const
+void ExpandDecorator::unexpected(const Span& sp, const AST::Attribute& mi, const char* loc_str) const
{
WARNING(sp, W0000, "Unexpected attribute " << mi.name() << " on " << loc_str);
}
-void Expand_Attr(const Span& sp, const ::AST::MetaItem& a, AttrStage stage, ::std::function<void(const Span& sp, const ExpandDecorator& d,const ::AST::MetaItem& a)> f)
+void Expand_Attr(const Span& sp, const ::AST::Attribute& a, AttrStage stage, ::std::function<void(const Span& sp, const ExpandDecorator& d,const ::AST::Attribute& a)> f)
{
for( auto& d : g_decorators ) {
if( d.first == a.name() ) {
@@ -59,29 +59,30 @@ void Expand_Attr(const Span& sp, const ::AST::MetaItem& a, AttrStage stage, ::s
}
}
}
-void Expand_Attrs(/*const */::AST::MetaItems& attrs, AttrStage stage, ::std::function<void(const Span& sp, const ExpandDecorator& d,const ::AST::MetaItem& a)> f)
+void Expand_Attrs(/*const */::AST::AttributeList& attrs, AttrStage stage, ::std::function<void(const Span& sp, const ExpandDecorator& d,const ::AST::Attribute& a)> f)
{
for( auto& a : attrs.m_items )
{
if( a.name() == "cfg_attr" ) {
- if( check_cfg(attrs.m_span, a.items().at(0)) ) {
+ if( check_cfg(a.span(), a.items().at(0)) ) {
+ // Wait? Why move?
auto inner_attr = mv$(a.items().at(1));
- Expand_Attr(attrs.m_span, inner_attr, stage, f);
+ Expand_Attr(inner_attr.span(), inner_attr, stage, f);
a = mv$(inner_attr);
}
else {
}
}
else {
- Expand_Attr(attrs.m_span, a, stage, f);
+ Expand_Attr(a.span(), a, stage, f);
}
}
}
-void Expand_Attrs(::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate, const ::AST::Path& path, ::AST::Module& mod, ::AST::Item& item)
+void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& crate, const ::AST::Path& path, ::AST::Module& mod, ::AST::Item& item)
{
Expand_Attrs(attrs, stage, [&](const auto& sp, const auto& d, const auto& a){ if(!item.is_None()) d.handle(sp, a, crate, path, mod, item); });
}
-void Expand_Attrs(::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate, ::AST::Module& mod, ::AST::ImplDef& impl)
+void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& crate, ::AST::Module& mod, ::AST::ImplDef& impl)
{
Expand_Attrs(attrs, stage, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, mod, impl); });
}
@@ -271,13 +272,15 @@ void Expand_Type(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:
(TraitObject,
for(auto& p : e.traits)
{
- Expand_Path(crate, modstack, mod, p);
+ // TODO: p.hrbs? Not needed until types are in those
+ Expand_Path(crate, modstack, mod, p.path);
}
),
(ErasedType,
for(auto& p : e.traits)
{
- Expand_Path(crate, modstack, mod, p);
+ // TODO: p.hrbs?
+ Expand_Path(crate, modstack, mod, p.path);
}
)
)
@@ -585,13 +588,13 @@ struct CExpandExpr:
::std::vector< ::AST::ExprNode_Match_Arm> arms;
// - `Some(pattern ) => code`
arms.push_back( ::AST::ExprNode_Match_Arm(
- ::make_vec1( ::AST::Pattern(::AST::Pattern::TagNamedTuple(), path_Some, ::make_vec1( mv$(node.m_pattern) ) ) ),
+ ::make_vec1( ::AST::Pattern(::AST::Pattern::TagNamedTuple(), node.span(), path_Some, ::make_vec1( mv$(node.m_pattern) ) ) ),
nullptr,
mv$(node.m_code)
) );
// - `None => break label`
arms.push_back( ::AST::ExprNode_Match_Arm(
- ::make_vec1( ::AST::Pattern(::AST::Pattern::TagValue(), ::AST::Pattern::Value::make_Named(path_None)) ),
+ ::make_vec1( ::AST::Pattern(::AST::Pattern::TagValue(), node.span(), ::AST::Pattern::Value::make_Named(path_None)) ),
nullptr,
::AST::ExprNodeP(new ::AST::ExprNode_Flow(::AST::ExprNode_Flow::BREAK, node.m_label, nullptr))
) );
@@ -602,7 +605,7 @@ struct CExpandExpr:
::make_vec1( mv$(node.m_cond) )
)),
::make_vec1(::AST::ExprNode_Match_Arm(
- ::make_vec1( ::AST::Pattern(::AST::Pattern::TagBind(), "it") ),
+ ::make_vec1( ::AST::Pattern(::AST::Pattern::TagBind(), node.span(), "it") ),
nullptr,
::AST::ExprNodeP(new ::AST::ExprNode_Loop(
node.m_label,
@@ -796,13 +799,13 @@ struct CExpandExpr:
::std::vector< ::AST::ExprNode_Match_Arm> arms;
// `Ok(v) => v,`
arms.push_back(::AST::ExprNode_Match_Arm(
- ::make_vec1( ::AST::Pattern(::AST::Pattern::TagNamedTuple(), path_Ok, ::make_vec1( ::AST::Pattern(::AST::Pattern::TagBind(), "v") )) ),
+ ::make_vec1( ::AST::Pattern(::AST::Pattern::TagNamedTuple(), node.span(), path_Ok, ::make_vec1( ::AST::Pattern(::AST::Pattern::TagBind(), node.span(), "v") )) ),
nullptr,
::AST::ExprNodeP( new ::AST::ExprNode_NamedValue( ::AST::Path(::AST::Path::TagLocal(), "v") ) )
));
// `Err(e) => return Err(From::from(e)),`
arms.push_back(::AST::ExprNode_Match_Arm(
- ::make_vec1( ::AST::Pattern(::AST::Pattern::TagNamedTuple(), path_Err, ::make_vec1( ::AST::Pattern(::AST::Pattern::TagBind(), "e") )) ),
+ ::make_vec1( ::AST::Pattern(::AST::Pattern::TagNamedTuple(), node.span(), path_Err, ::make_vec1( ::AST::Pattern(::AST::Pattern::TagBind(), node.span(), "e") )) ),
nullptr,
::AST::ExprNodeP(new ::AST::ExprNode_Flow(
::AST::ExprNode_Flow::RETURN,
@@ -858,6 +861,8 @@ void Expand_GenericParams(::AST::Crate& crate, LList<const AST::Module*> modstac
for(auto& bound : params.bounds())
{
TU_MATCHA( (bound), (be),
+ (None,
+ ),
(Lifetime,
),
(TypeLifetime,
@@ -1293,7 +1298,7 @@ void Expand(::AST::Crate& crate)
crate.m_extern_crates.at("std").with_all_macros([&](const auto& name, const auto& mac) {
crate.m_root_module.add_macro_import( name, mac );
});
- crate.m_root_module.add_ext_crate(false, "std", "std", ::AST::MetaItems {});
+ crate.m_root_module.add_ext_crate(false, "std", "std", ::AST::AttributeList {});
break;
case ::AST::Crate::LOAD_CORE:
if( crate.m_prelude_path == AST::Path() )
@@ -1301,7 +1306,7 @@ void Expand(::AST::Crate& crate)
crate.m_extern_crates.at("core").with_all_macros([&](const auto& name, const auto& mac) {
crate.m_root_module.add_macro_import( name, mac );
});
- crate.m_root_module.add_ext_crate(false, "core", "core", ::AST::MetaItems {});
+ crate.m_root_module.add_ext_crate(false, "core", "core", ::AST::AttributeList {});
break;
case ::AST::Crate::LOAD_NONE:
break;
diff --git a/src/expand/proc_macro.cpp b/src/expand/proc_macro.cpp
index d34a91a5..969f75b0 100644
--- a/src/expand/proc_macro.cpp
+++ b/src/expand/proc_macro.cpp
@@ -24,7 +24,7 @@
# include <sys/wait.h>
#endif
-#if defined(__OpenBSD__) || defined(__NetBSD__)
+#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
extern char **environ;
#endif
@@ -35,7 +35,7 @@ class Decorator_ProcMacroDerive:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::MetaItem& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
{
if( i.is_None() )
return;
@@ -345,45 +345,41 @@ namespace {
),
(TraitObject,
m_pmi.send_symbol("(");
- if( te.hrls.size() > 0 )
- {
- m_pmi.send_ident("for");
- m_pmi.send_symbol("<");
- for(const auto& v : te.hrls)
- {
- m_pmi.send_lifetime(v.c_str());
- m_pmi.send_symbol(",");
- }
- m_pmi.send_symbol(">");
- }
for(const auto& t : te.traits)
{
- this->visit_path(t);
+ this->visit_hrbs(t.hrbs);
+ this->visit_path(t.path);
m_pmi.send_symbol("+");
}
+ // TODO: Lifetimes
m_pmi.send_symbol(")");
),
(ErasedType,
m_pmi.send_ident("impl");
- if( te.hrls.size() > 0 )
- {
- m_pmi.send_ident("for");
- m_pmi.send_symbol("<");
- for(const auto& v : te.hrls)
- {
- m_pmi.send_lifetime(v.c_str());
- m_pmi.send_symbol(",");
- }
- m_pmi.send_symbol(">");
- }
for(const auto& t : te.traits)
{
- this->visit_path(t);
+ this->visit_hrbs(t.hrbs);
+ this->visit_path(t.path);
m_pmi.send_symbol("+");
}
+ // TODO: Lifetimes
)
)
}
+ void visit_hrbs(const AST::HigherRankedBounds& hrbs)
+ {
+ if( !hrbs.empty() )
+ {
+ m_pmi.send_ident("for");
+ m_pmi.send_symbol("<");
+ for(const auto& v : hrbs.m_lifetimes)
+ {
+ m_pmi.send_lifetime(v.name().name.c_str());
+ m_pmi.send_symbol(",");
+ }
+ m_pmi.send_symbol(">");
+ }
+ }
void visit_path(const AST::Path& path, bool is_expr=false)
{
@@ -445,7 +441,7 @@ namespace {
m_pmi.send_symbol("<");
for(const auto& l : e.args().m_lifetimes)
{
- m_pmi.send_lifetime(l.c_str());
+ m_pmi.send_lifetime(l.name().name.c_str());
m_pmi.send_symbol(",");
}
for(const auto& t : e.args().m_types)
@@ -475,7 +471,7 @@ namespace {
{
if( !is_first )
m_pmi.send_symbol(",");
- m_pmi.send_lifetime(p.c_str());
+ m_pmi.send_lifetime(p.name().name.c_str());
is_first = false;
}
// Types
@@ -609,7 +605,7 @@ namespace {
TODO(sp, "ExprNode_UniOp");
}
- void visit_attrs(const ::AST::MetaItems& attrs)
+ void visit_attrs(const ::AST::AttributeList& attrs)
{
for(const auto& a : attrs.m_items)
{
@@ -622,7 +618,7 @@ namespace {
}
}
}
- void visit_meta_item(const ::AST::MetaItem& i)
+ void visit_meta_item(const ::AST::Attribute& i)
{
m_pmi.send_ident(i.name().c_str());
if( i.has_noarg() ) {
diff --git a/src/expand/std_prelude.cpp b/src/expand/std_prelude.cpp
index e12a441c..6b81b71e 100644
--- a/src/expand/std_prelude.cpp
+++ b/src/expand/std_prelude.cpp
@@ -8,8 +8,8 @@ class Decorator_NoStd:
{
public:
AttrStage stage() const override { return AttrStage::Pre; }
-
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override {
+
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
if( crate.m_load_std != AST::Crate::LOAD_STD && crate.m_load_std != AST::Crate::LOAD_CORE ) {
ERROR(sp, E0000, "Invalid use of #![no_std] with itself or #![no_core]");
}
@@ -22,7 +22,7 @@ class Decorator_NoCore:
public:
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
if( crate.m_load_std != AST::Crate::LOAD_STD && crate.m_load_std != AST::Crate::LOAD_NONE ) {
ERROR(sp, E0000, "Invalid use of #![no_core] with itself or #![no_std]");
}
@@ -42,7 +42,7 @@ class Decorator_NoPrelude:
public:
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
if( i.is_Module() ) {
i.as_Module().m_insert_prelude = false;
}
@@ -58,7 +58,7 @@ class Decorator_PreludeImport:
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
if( i.is_Use() ) {
const auto& p = i.as_Use().path;
// TODO: Ensure that this statement is a glob (has a name of "")
diff --git a/src/expand/test.cpp b/src/expand/test.cpp
index 12bfbb7d..9497c692 100644
--- a/src/expand/test.cpp
+++ b/src/expand/test.cpp
@@ -14,7 +14,7 @@ class CTestHandler:
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
if( ! i.is_Function() ) {
ERROR(sp, E0000, "#[test] can only be put on functions - found on " << i.tag_str());
}
@@ -42,7 +42,7 @@ class CTestHandler_SP:
{
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
if( ! i.is_Function() ) {
ERROR(sp, E0000, "#[should_panic] can only be put on functions - found on " << i.tag_str());
}
@@ -75,7 +75,7 @@ class CTestHandler_Ignore:
{
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
if( ! i.is_Function() ) {
ERROR(sp, E0000, "#[should_panic] can only be put on functions - found on " << i.tag_str());
}
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index 326debd7..17a93730 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -8,13 +8,12 @@
//#define DISABLE_DEBUG // Disable debug for this function - too hot
#include "hir.hpp"
#include "main_bindings.hpp"
-#include <serialiser_texttree.hpp>
#include <mir/mir.hpp>
#include <macro_rules/macro_rules.hpp>
#include "serialise_lowlevel.hpp"
#include <typeinfo>
-namespace {
+//namespace {
template<typename T>
struct D
@@ -114,6 +113,7 @@ namespace {
}
+ ::HIR::LifetimeRef deserialise_lifetimeref();
::HIR::TypeRef deserialise_type();
::HIR::SimplePath deserialise_simplepath();
::HIR::PathParams deserialise_pathparams();
@@ -310,15 +310,29 @@ namespace {
}
::Token deserialise_token() {
- ::Token tok;
- // HACK: Hand off to old serialiser code
- auto s = m_in.read_string();
- ::std::stringstream tmp(s);
+ auto ty = static_cast<enum eTokenType>( m_in.read_tag() );
+ auto d = deserialise_tokendata();
+ return ::Token(ty, ::std::move(d), {});
+ }
+ ::Token::Data deserialise_tokendata() {
+ auto tag = static_cast< ::Token::Data::Tag>( m_in.read_tag() );
+ switch(tag)
{
- Deserialiser_TextTree ser(tmp);
- tok.deserialise( ser );
+ case ::Token::Data::TAG_None:
+ return ::Token::Data::make_None({});
+ case ::Token::Data::TAG_String:
+ return ::Token::Data::make_String( m_in.read_string() );
+ case ::Token::Data::TAG_Integer: {
+ auto dty = static_cast<eCoreType>(m_in.read_tag());
+ return ::Token::Data::make_Integer({ dty, m_in.read_u64c() });
+ }
+ case ::Token::Data::TAG_Float: {
+ auto dty = static_cast<eCoreType>(m_in.read_tag());
+ return ::Token::Data::make_Float({ dty, m_in.read_double() });
+ }
+ default:
+ throw ::std::runtime_error(FMT("Invalid Token data tag - " << tag));
}
- return tok;
}
::HIR::Literal deserialise_literal();
@@ -718,6 +732,11 @@ namespace {
template<> DEF_D( ::HIR::ExternLibrary, return d.deserialise_extlib(); )
+ ::HIR::LifetimeRef HirDeserialiser::deserialise_lifetimeref()
+ {
+ return { static_cast<uint32_t>(m_in.read_count()) };
+ }
+
::HIR::TypeRef HirDeserialiser::deserialise_type()
{
::HIR::TypeRef rv;
@@ -741,13 +760,13 @@ namespace {
_(TraitObject, {
deserialise_traitpath(),
deserialise_vec< ::HIR::GenericPath>(),
- "" // TODO: m_lifetime
+ deserialise_lifetimeref()
})
_(ErasedType, {
deserialise_path(),
static_cast<unsigned int>(m_in.read_count()),
deserialise_vec< ::HIR::TraitPath>(),
- "" // TODO: m_lifetime
+ deserialise_lifetimeref()
})
_(Array, {
deserialise_ptr< ::HIR::TypeRef>(),
@@ -761,6 +780,7 @@ namespace {
deserialise_vec< ::HIR::TypeRef>()
)
_(Borrow, {
+ deserialise_lifetimeref(),
static_cast< ::HIR::BorrowType>( m_in.read_tag() ),
deserialise_ptr< ::HIR::TypeRef>()
})
@@ -1227,7 +1247,7 @@ namespace {
return rv;
}
-}
+//}
::HIR::CratePtr HIR_Deserialise(const ::std::string& filename, const ::std::string& loaded_name)
{
diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp
index 3bbbdd95..874a80a7 100644
--- a/src/hir/dump.cpp
+++ b/src/hir/dump.cpp
@@ -163,6 +163,7 @@ namespace {
for(const auto& var : e->variants)
{
m_os << indent() << var.name;
+ m_os << ",\n";
}
}
else
@@ -178,8 +179,8 @@ namespace {
{
m_os << " " << var.type << (var.is_struct ? "/*struct*/" : "");
}
+ m_os << ",\n";
}
- m_os << ",\n";
}
dec_indent();
m_os << indent() << "}\n";
diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp
index 3069ae1d..33726093 100644
--- a/src/hir/expr.hpp
+++ b/src/hir/expr.hpp
@@ -620,16 +620,12 @@ struct ExprNode_Literal:
m_res_type = ::HIR::TypeRef::Data::make_Primitive( ::HIR::CoreType::Bool );
),
(String,
- m_res_type = ::HIR::TypeRef::Data::make_Borrow({
- ::HIR::BorrowType::Shared,
- box$( ::HIR::TypeRef( ::HIR::TypeRef::Data::make_Primitive(::HIR::CoreType::Str) ) )
- });
+ // TODO: &'static
+ m_res_type = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ::HIR::TypeRef(::HIR::CoreType::Str) );
),
(ByteString,
- m_res_type = ::HIR::TypeRef::Data::make_Borrow({
- ::HIR::BorrowType::Shared,
- box$( ::HIR::TypeRef::new_array( ::HIR::CoreType::U8, e.size() ) )
- });
+ // TODO: &'static
+ m_res_type = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ::HIR::TypeRef::new_array(::HIR::CoreType::U8, e.size()) );
)
)
}
diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp
index ce9b2490..4def1a41 100644
--- a/src/hir/from_ast.cpp
+++ b/src/hir/from_ast.cpp
@@ -15,9 +15,10 @@
#include "visitor.hpp"
#include <macro_rules/macro_rules.hpp>
#include <hir/item_path.hpp>
+#include <limits.h>
::HIR::Module LowerHIR_Module(const ::AST::Module& module, ::HIR::ItemPath path, ::std::vector< ::HIR::SimplePath> traits = {});
-::HIR::Function LowerHIR_Function(::HIR::ItemPath path, const ::AST::MetaItems& attrs, const ::AST::Function& f, const ::HIR::TypeRef& self_type);
+::HIR::Function LowerHIR_Function(::HIR::ItemPath path, const ::AST::AttributeList& attrs, const ::AST::Function& f, const ::HIR::TypeRef& self_type);
::HIR::PathParams LowerHIR_PathParams(const Span& sp, const ::AST::PathParams& src_params, bool allow_assoc);
::HIR::TraitPath LowerHIR_TraitPath(const Span& sp, const ::AST::Path& path);
@@ -27,6 +28,11 @@
::HIR::Crate* g_crate_ptr = nullptr;
// --------------------------------------------------------------------
+::std::string LowerHIR_LifetimeRef(const ::AST::LifetimeRef& r)
+{
+ return r.name().name;
+}
+
::HIR::GenericParams LowerHIR_GenericParams(const ::AST::GenericParams& gp, bool* self_is_sized)
{
::HIR::GenericParams rv;
@@ -40,33 +46,35 @@
}
if( gp.lft_params().size() > 0 )
{
- for(const auto& lft_name : gp.lft_params())
- rv.m_lifetimes.push_back( lft_name );
+ for(const auto& lft_def : gp.lft_params())
+ rv.m_lifetimes.push_back( lft_def.name().name );
}
if( gp.bounds().size() > 0 )
{
for(const auto& bound : gp.bounds())
{
TU_MATCH(::AST::GenericBound, (bound), (e),
+ (None,
+ ),
(Lifetime,
rv.m_bounds.push_back(::HIR::GenericBound::make_Lifetime({
- e.test,
- e.bound
+ LowerHIR_LifetimeRef(e.test),
+ LowerHIR_LifetimeRef(e.bound)
}));
),
(TypeLifetime,
rv.m_bounds.push_back(::HIR::GenericBound::make_TypeLifetime({
LowerHIR_Type(e.type),
- e.bound
+ LowerHIR_LifetimeRef(e.bound)
}));
),
(IsTrait,
auto type = LowerHIR_Type(e.type);
- // TODO: Check for `Sized`
+ // TODO: Check if this trait is `Sized` and ignore if it is
- rv.m_bounds.push_back(::HIR::GenericBound::make_TraitBound({ mv$(type), LowerHIR_TraitPath(bound.span, e.trait) }));
- rv.m_bounds.back().as_TraitBound().trait.m_hrls = e.hrls;
+ rv.m_bounds.push_back(::HIR::GenericBound::make_TraitBound({ /*LowerHIR_HigherRankedBounds(e.outer_hrbs),*/ mv$(type), LowerHIR_TraitPath(bound.span, e.trait) }));
+ //rv.m_bounds.back().as_TraitBound().trait.m_hrls = LowerHIR_HigherRankedBounds(e.inner_hrbs);
),
(MaybeTrait,
auto type = LowerHIR_Type(e.type);
@@ -478,7 +486,7 @@
};
)
)
- throw ::std::runtime_error("TODO: LowerHIR_Pattern");
+ throw "unreachable";
}
::HIR::ExprPtr LowerHIR_Expr(const ::std::shared_ptr< ::AST::ExprNode>& e)
@@ -722,7 +730,9 @@
{
if( ptr->m_datatype == CORETYPE_UINT || ptr->m_datatype == CORETYPE_ANY )
{
- // TODO: Limit check.
+ if( ptr->m_value > UINT_MAX ) {
+ ERROR(ty.span(), E0000, "Array size out of bounds - " << ptr->m_value << " > " << UINT_MAX);
+ }
auto size_val = static_cast<unsigned int>( ptr->m_value );
return ::HIR::TypeRef::new_array( mv$(inner), size_val );
}
@@ -752,47 +762,59 @@
}
),
(TraitObject,
- //if( e.hrls.size() > 0 )
- // TODO(ty.span(), "TraitObjects with HRLS - " << ty);
::HIR::TypeRef::Data::Data_TraitObject v;
// TODO: Lifetime
for(const auto& t : e.traits)
{
- DEBUG("t = " << t);
- const auto& tb = t.binding().as_Trait();
+ DEBUG("t = " << t.path);
+ const auto& tb = t.path.binding().as_Trait();
assert( tb.trait_ || tb.hir );
- if( (tb.trait_ ? tb.trait_->is_marker() : tb.hir->m_is_marker) ) {
+ if( (tb.trait_ ? tb.trait_->is_marker() : tb.hir->m_is_marker) )
+ {
if( tb.hir ) {
DEBUG(tb.hir->m_values.size());
}
- v.m_markers.push_back( LowerHIR_GenericPath(ty.span(), t) );
+ // TODO: If this has HRBs, what?
+ v.m_markers.push_back( LowerHIR_GenericPath(ty.span(), t.path) );
}
else {
// TraitPath -> GenericPath -> SimplePath
if( v.m_trait.m_path.m_path.m_components.size() > 0 ) {
ERROR(ty.span(), E0000, "Multiple data traits in trait object - " << ty);
}
- v.m_trait = LowerHIR_TraitPath(ty.span(), t);
+ // TODO: Handle HRBs
+ v.m_trait = LowerHIR_TraitPath(ty.span(), t.path);
}
}
return ::HIR::TypeRef( ::HIR::TypeRef::Data::make_TraitObject( mv$(v) ) );
),
(ErasedType,
- //if( e.hrls.size() > 0 )
- // TODO(ty.span(), "ErasedType with HRLS - " << ty);
ASSERT_BUG(ty.span(), e.traits.size() > 0, "ErasedType with no traits");
::std::vector< ::HIR::TraitPath> traits;
for(const auto& t : e.traits)
{
- DEBUG("t = " << t);
- traits.push_back( LowerHIR_TraitPath(ty.span(), t) );
+ DEBUG("t = " << t.path);
+ // TODO: Pass the HRBs down
+ traits.push_back( LowerHIR_TraitPath(ty.span(), t.path) );
+ }
+ ::HIR::LifetimeRef lft;
+ if( e.lifetimes.size() == 0 )
+ {
+ }
+ else if( e.lifetimes.size() == 1 )
+ {
+ // TODO: Convert the lifetime reference
+ }
+ else
+ {
+ TODO(ty.span(), "Handle multiple lifetime parameters - " << ty);
}
// Leave `m_origin` until the bind pass
return ::HIR::TypeRef( ::HIR::TypeRef::Data::make_ErasedType(::HIR::TypeRef::Data::Data_ErasedType {
::HIR::Path(::HIR::SimplePath()), 0,
mv$(traits),
- ::HIR::LifetimeRef() // TODO: Lifetime ref
+ lft
} ) );
),
(Function,
@@ -833,7 +855,7 @@ namespace {
}
}
-::HIR::Struct LowerHIR_Struct(::HIR::ItemPath path, const ::AST::Struct& ent)
+::HIR::Struct LowerHIR_Struct(::HIR::ItemPath path, const ::AST::Struct& ent, const ::AST::AttributeList& attrs)
{
TRACE_FUNCTION_F(path);
::HIR::Struct::Data data;
@@ -858,15 +880,46 @@ namespace {
)
)
+ auto struct_repr = ::HIR::Struct::Repr::Rust;
+ if( const auto* attr_repr = attrs.get("repr") )
+ {
+ ASSERT_BUG(Span(), attr_repr->has_sub_items(), "#[repr] attribute malformed, " << *attr_repr);
+ bool is_c = false;
+ bool is_packed = false;
+ ASSERT_BUG(Span(), attr_repr->items().size() > 0, "#[repr] attribute malformed, " << *attr_repr);
+ for( const auto& a : attr_repr->items() )
+ {
+ ASSERT_BUG(Span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
+ const auto& repr_str = a.name();
+ if( repr_str == "C" ) {
+ is_c = true;
+ }
+ else if( repr_str == "packed" ) {
+ is_packed = true;
+ }
+ else {
+ TODO(a.span(), "Handle struct repr '" << repr_str << "'");
+ }
+ }
+
+ if( is_packed ) {
+ struct_repr = ::HIR::Struct::Repr::Packed;
+ }
+ else if( is_c ) {
+ struct_repr = ::HIR::Struct::Repr::C;
+ }
+ else {
+ }
+ }
+
return ::HIR::Struct {
LowerHIR_GenericParams(ent.params(), nullptr),
- // TODO: Get repr from attributes
- ::HIR::Struct::Repr::Rust,
+ struct_repr,
mv$(data)
};
}
-::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::MetaItems& attrs, ::std::function<void(::std::string, ::HIR::Struct)> push_struct)
+::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::AttributeList& attrs, ::std::function<void(::std::string, ::HIR::Struct)> push_struct)
{
// 1. Figure out what sort of enum this is (value or data)
@@ -933,7 +986,6 @@ namespace {
repr = ::HIR::Enum::Repr::Usize;
}
else {
- // TODO: Other repr types
ERROR(Span(), E0000, "Unknown enum repr '" << repr_str << "'");
}
}
@@ -1017,7 +1069,7 @@ namespace {
mv$(data)
};
}
-::HIR::Union LowerHIR_Union(::HIR::ItemPath path, const ::AST::Union& f, const ::AST::MetaItems& attrs)
+::HIR::Union LowerHIR_Union(::HIR::ItemPath path, const ::AST::Union& f, const ::AST::AttributeList& attrs)
{
auto repr = ::HIR::Union::Repr::Rust;
@@ -1031,7 +1083,7 @@ namespace {
repr = ::HIR::Union::Repr::C;
}
else {
- // TODO: Error?
+ ERROR(attr_repr->span(), E0000, "Unknown union repr '" << repr_str << "'");
}
}
@@ -1056,8 +1108,8 @@ namespace {
::std::string lifetime;
::std::vector< ::HIR::TraitPath> supertraits;
for(const auto& st : f.supertraits()) {
- if( st.ent.is_valid() ) {
- supertraits.push_back( LowerHIR_TraitPath(st.sp, st.ent) );
+ if( st.ent.path.is_valid() ) {
+ supertraits.push_back( LowerHIR_TraitPath(st.sp, st.ent.path) );
}
else {
lifetime = "static";
@@ -1153,7 +1205,7 @@ namespace {
return rv;
}
-::HIR::Function LowerHIR_Function(::HIR::ItemPath p, const ::AST::MetaItems& attrs, const ::AST::Function& f, const ::HIR::TypeRef& self_type)
+::HIR::Function LowerHIR_Function(::HIR::ItemPath p, const ::AST::AttributeList& attrs, const ::AST::Function& f, const ::HIR::TypeRef& self_type)
{
static Span sp;
@@ -1240,7 +1292,7 @@ namespace {
// Leave linkage.name as empty
}
- // If there's no code, demangle the name (TODO: By ABI) and set linkage.
+ // If there's no code, mangle the name (According to the ABI) and set linkage.
if( linkage.name == "" && ! f.code().is_valid() )
{
linkage.name = p.get_name();
@@ -1336,10 +1388,10 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
}
),
(Impl,
- //TODO(sp, "Expand Item::Impl");
+ // NOTE: impl blocks are handled in a second pass
),
(NegImpl,
- //TODO(sp, "Expand Item::NegImpl");
+ // NOTE: impl blocks are handled in a second pass
),
(Use,
// Ignore - The index is used to add `Import`s
@@ -1365,7 +1417,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
}
else {
}
- _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Struct(item_path, e) );
+ _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Struct(item_path, e, item.data.attrs) );
),
(Enum,
auto enm = LowerHIR_Enum(item_path, e, item.data.attrs, [&](auto name, auto str){ _add_mod_ns_item(mod, name, item.is_pub, mv$(str)); });
@@ -1771,7 +1823,8 @@ public:
// Set all pointers in the HIR to the correct (now fixed) locations
IndexVisitor(rv).visit_crate( rv );
- // TODO: If the current crate is libcore, store the paths to various non-lang ops items
+ // HACK: If the current crate is libcore, store the paths to various non-lang ops items
+ // - Some operators aren't tagged with #[lang], so this works around that
if( crate.m_crate_name == "core" )
{
struct H {
@@ -1831,7 +1884,7 @@ public:
}
}
};
- // TODO: Check for existing defintions of lang items
+ // Check for existing defintions of lang items before adding magic ones
if( rv.m_lang_items.count("boxed_trait") == 0 )
{
rv.m_lang_items.insert(::std::make_pair( ::std::string("boxed_trait"), H::resolve_path(rv, false, {"ops", "Boxed"}) ));
diff --git a/src/hir/path.hpp b/src/hir/path.hpp
index addfba05..206b5d5b 100644
--- a/src/hir/path.hpp
+++ b/src/hir/path.hpp
@@ -97,6 +97,7 @@ struct SimplePath
struct PathParams
{
+ //::std::vector<LifetimeRef> m_lifetimes;
::std::vector<TypeRef> m_types;
PathParams();
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index f1398aa3..55cd579f 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -7,12 +7,11 @@
*/
#include "hir.hpp"
#include "main_bindings.hpp"
-#include <serialiser_texttree.hpp>
#include <macro_rules/macro_rules.hpp>
#include <mir/mir.hpp>
#include "serialise_lowlevel.hpp"
-namespace {
+//namespace {
class HirSerialiser
{
::HIR::serialise::Writer& m_out;
@@ -87,6 +86,10 @@ namespace {
void serialise(uint64_t v) { m_out.write_u64c(v); };
void serialise(int64_t v) { m_out.write_i64c(v); };
+ void serialise(const ::HIR::LifetimeRef& lr)
+ {
+ m_out.write_count(lr.binding);
+ }
void serialise_type(const ::HIR::TypeRef& ty)
{
m_out.write_tag( ty.m_data.tag() );
@@ -111,7 +114,7 @@ namespace {
m_out.write_count(e.m_markers.size());
for(const auto& m : e.m_markers)
serialise_genericpath(m);
- //write_string(e.lifetime); // TODO: Need a better type
+ serialise(e.m_lifetime);
),
(ErasedType,
serialise_path(e.m_origin);
@@ -120,6 +123,7 @@ namespace {
m_out.write_count(e.m_traits.size());
for(const auto& t : e.m_traits)
serialise_traitpath(t);
+ serialise(e.m_lifetime);
),
(Array,
assert(e.size_val != ~0u);
@@ -135,6 +139,7 @@ namespace {
serialise_type(st);
),
(Borrow,
+ serialise(e.lifetime);
m_out.write_tag(static_cast<int>(e.type));
serialise_type(*e.inner);
),
@@ -440,14 +445,31 @@ namespace {
)
}
void serialise(const ::Token& tok) {
- // HACK: Hand off to old serialiser code
- ::std::stringstream tmp;
+ m_out.write_tag(tok.m_type);
+ serialise(tok.m_data);
+ // TODO: Position information.
+ }
+ void serialise(const ::Token::Data& td) {
+ m_out.write_tag(td.tag());
+ switch(td.tag())
{
- Serialiser_TextTree ser(tmp);
- tok.serialise( ser );
+ case ::Token::Data::TAGDEAD: throw "";
+ TU_ARM(td, None, _e) {
+ } break;
+ TU_ARM(td, String, e) {
+ m_out.write_string(e);
+ } break;
+ TU_ARM(td, Integer, e) {
+ m_out.write_tag(e.m_datatype);
+ m_out.write_u64c(e.m_intval);
+ } break;
+ TU_ARM(td, Float, e) {
+ m_out.write_tag(e.m_datatype);
+ m_out.write_double(e.m_floatval);
+ } break;
+ TU_ARM(td, Fragment, e)
+ assert(!"Serialising interpolated macro fragment");
}
-
- m_out.write_string(tmp.str());
}
void serialise(const ::HIR::Literal& lit)
@@ -1005,7 +1027,7 @@ namespace {
serialise_type(at.m_default);
}
};
-}
+//}
void HIR_Serialise(const ::std::string& filename, const ::HIR::Crate& crate)
{
diff --git a/src/hir/type.cpp b/src/hir/type.cpp
index 033e7bf5..6f826111 100644
--- a/src/hir/type.cpp
+++ b/src/hir/type.cpp
@@ -112,8 +112,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
}
for(const auto& tr : e.m_markers)
os << "+" << tr;
- if( e.m_lifetime.name != "" )
- os << "+ '" << e.m_lifetime.name;
+ if( e.m_lifetime != LifetimeRef::new_static() )
+ os << "+" << e.m_lifetime;
os << ")";
),
(ErasedType,
@@ -123,8 +123,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
os << "+";
os << tr;
}
- if( e.m_lifetime.name != "" )
- os << "+ '" << e.m_lifetime.name;
+ if( e.m_lifetime != LifetimeRef::new_static() )
+ os << "+ '" << e.m_lifetime;
os << "/*" << e.m_origin << "#" << e.m_index << "*/";
),
(Array,
@@ -860,7 +860,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
return ::HIR::TypeRef( Data::make_Tuple(mv$(types)) );
),
(Borrow,
- return ::HIR::TypeRef( Data::make_Borrow({e.type, box$(e.inner->clone())}) );
+ return ::HIR::TypeRef( Data::make_Borrow({e.lifetime, e.type, box$(e.inner->clone())}) );
),
(Pointer,
return ::HIR::TypeRef( Data::make_Pointer({e.type, box$(e.inner->clone())}) );
diff --git a/src/hir/type.hpp b/src/hir/type.hpp
index 329af650..480b32c4 100644
--- a/src/hir/type.hpp
+++ b/src/hir/type.hpp
@@ -84,10 +84,47 @@ extern ::std::ostream& operator<<(::std::ostream& os, const BorrowType& bt);
struct LifetimeRef
{
- ::std::string name;
+ static const uint32_t UNKNOWN = 0;
+ static const uint32_t STATIC = 0xFFFF;
+
+ // Values below 2^16 are parameters/static, values above are per-function region IDs allocated during region inferrence.
+ uint32_t binding = UNKNOWN;
+
+ static LifetimeRef new_static() {
+ LifetimeRef rv;
+ rv.binding = STATIC;
+ return rv;
+ }
bool operator==(const LifetimeRef& x) const {
- return name == x.name;
+ return binding == x.binding;
+ }
+ bool operator!=(const LifetimeRef& x) const {
+ return !(*this == x);
+ }
+ friend ::std::ostream& operator<<(::std::ostream& os, const LifetimeRef& x) {
+ if( x.binding == UNKNOWN )
+ {
+ os << "'_";
+ }
+ else if( x.binding == STATIC )
+ {
+ os << "'static";
+ }
+ else if( x.binding < 0xFFFF )
+ {
+ switch( x.binding & 0xFF00 )
+ {
+ case 0: os << "'I" << (x.binding & 0xFF); break;
+ case 1: os << "'M" << (x.binding & 0xFF); break;
+ default: os << "'unk" << x.binding; break;
+ }
+ }
+ else
+ {
+ os << "'_" << (x.binding - 0x1000);
+ }
+ return os;
}
};
@@ -178,6 +215,7 @@ public:
}),
(Tuple, ::std::vector<TypeRef>),
(Borrow, struct {
+ ::HIR::LifetimeRef lifetime;
::HIR::BorrowType type;
::std::unique_ptr<TypeRef> inner;
}),
@@ -234,7 +272,7 @@ public:
return TypeRef(Data::make_Infer({idx, ty_class}));
}
static TypeRef new_borrow(BorrowType bt, TypeRef inner) {
- return TypeRef(Data::make_Borrow({bt, box$(mv$(inner))}));
+ return TypeRef(Data::make_Borrow({ ::HIR::LifetimeRef(), bt, box$(mv$(inner)) }));
}
static TypeRef new_pointer(BorrowType bt, TypeRef inner) {
return TypeRef(Data::make_Pointer({bt, box$(mv$(inner))}));
diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp
index f8a06013..5418da85 100644
--- a/src/hir_conv/bind.cpp
+++ b/src/hir_conv/bind.cpp
@@ -319,7 +319,7 @@ namespace {
}
}
}
- void visit_params(::HIR::GenericParams& params)
+ void visit_params(::HIR::GenericParams& params) override
{
static Span sp;
for(auto& bound : params.m_bounds)
@@ -422,7 +422,7 @@ namespace {
upper_visitor(uv)
{}
- void visit_generic_path(::HIR::Visitor::PathContext pc, ::HIR::GenericPath& p)
+ void visit_generic_path(::HIR::Visitor::PathContext pc, ::HIR::GenericPath& p) override
{
upper_visitor.visit_generic_path(p, pc);
}
diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp
index f3d23c47..82d4ab0e 100644
--- a/src/hir_conv/constant_evaluation.cpp
+++ b/src/hir_conv/constant_evaluation.cpp
@@ -246,6 +246,8 @@ namespace {
::HIR::Literal evaluate_constant_hir(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprNode& expr, ::HIR::TypeRef exp_type, ::std::vector< ::HIR::Literal> args)
{
+ // TODO: Force this function/tree through the entire pipeline so we can MIR it?
+ // - Requires a HUGE change to the way the compiler operates.
struct Visitor:
public ::HIR::ExprVisitor
{
@@ -1020,6 +1022,7 @@ namespace {
::HIR::Literal evaluate_constant_mir(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::MIR::Function& fcn, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args)
{
+ // TODO: Full-blown miri
TRACE_FUNCTION_F("exp=" << exp << ", args=" << args);
StaticTraitResolve resolve { crate };
@@ -1588,10 +1591,12 @@ namespace {
DEBUG("Array " << ty << " - size = " << e.size_val);
)
}
+ // TODO: Needs to be visited for MIR match generation to work
void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override
{
::HIR::Visitor::visit_constant(p, item);
+ // NOTE: Consteval needed here for MIR match generation to work
if( item.m_value )
{
//if( item.m_type.m_data.is_Primitive() )
@@ -1639,24 +1644,13 @@ namespace {
m_exp(exp)
{}
- void visit(::HIR::ExprNode_Let& node) override {
- ::HIR::ExprVisitorDef::visit(node);
- m_exp.visit_type(node.m_type);
+ void visit_type(::HIR::TypeRef& ty) override {
+ // Need to evaluate array sizes
+ m_exp.visit_type(ty);
}
- void visit(::HIR::ExprNode_Cast& node) override {
- ::HIR::ExprVisitorDef::visit(node);
- m_exp.visit_type(node.m_res_type);
- }
- // TODO: This shouldn't exist yet?
- void visit(::HIR::ExprNode_Unsize& node) override {
- ::HIR::ExprVisitorDef::visit(node);
- m_exp.visit_type(node.m_res_type);
- }
- void visit(::HIR::ExprNode_Closure& node) override {
- ::HIR::ExprVisitorDef::visit(node);
- m_exp.visit_type(node.m_return);
- for(auto& a : node.m_args)
- m_exp.visit_type(a.second);
+ void visit_path_params(::HIR::PathParams& pp) override {
+ // Explicit call to handle const params (eventually)
+ m_exp.visit_path_params(pp);
}
void visit(::HIR::ExprNode_ArraySized& node) override {
@@ -1668,15 +1662,6 @@ namespace {
node.m_size_val = static_cast<size_t>(val.as_Integer());
DEBUG("Array literal [?; " << node.m_size_val << "]");
}
-
- void visit(::HIR::ExprNode_CallPath& node) override {
- ::HIR::ExprVisitorDef::visit(node);
- m_exp.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE);
- }
- void visit(::HIR::ExprNode_CallMethod& node) override {
- ::HIR::ExprVisitorDef::visit(node);
- m_exp.visit_path_params(node.m_params);
- }
};
if( expr.get() != nullptr )
diff --git a/src/hir_conv/expand_type.cpp b/src/hir_conv/expand_type.cpp
index 6802cf22..dcdf79bd 100644
--- a/src/hir_conv/expand_type.cpp
+++ b/src/hir_conv/expand_type.cpp
@@ -208,11 +208,11 @@ public:
{}
// TODO: Use the other visitors.
- void visit_path(::HIR::Visitor::PathContext pc, ::HIR::Path& p)
+ void visit_path(::HIR::Visitor::PathContext pc, ::HIR::Path& p) override
{
upper_visitor.visit_path(p, pc);
}
- void visit_generic_path(::HIR::Visitor::PathContext pc, ::HIR::GenericPath& p)
+ void visit_generic_path(::HIR::Visitor::PathContext pc, ::HIR::GenericPath& p) override
{
upper_visitor.visit_generic_path(p, pc);
}
diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp
index 8a90c037..a0814e49 100644
--- a/src/hir_expand/closures.cpp
+++ b/src/hir_expand/closures.cpp
@@ -647,7 +647,7 @@ namespace {
//node.m_res_type = ::HIR::TypeRef( node.m_obj_path.clone() );
DEBUG("-- Object name: " << node.m_obj_path);
::HIR::TypeRef closure_type = ::HIR::TypeRef( ::HIR::GenericPath(node.m_obj_path.m_path.clone(), mv$(impl_path_params)) );
- closure_type.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Struct({ &closure_struct_ref });
+ closure_type.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Struct(&closure_struct_ref);
// - Args
::std::vector< ::HIR::Pattern> args_pat_inner;
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index 1a9382b6..22291123 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -246,11 +246,14 @@ void HMTypeInferrence::print_type(::std::ostream& os, const ::HIR::TypeRef& tr)
)
),
(Borrow,
+ os << "&";
+ if(e.lifetime != ::HIR::LifetimeRef())
+ os << e.lifetime << " ";
switch(e.type)
{
- case ::HIR::BorrowType::Shared: os << "&"; break;
- case ::HIR::BorrowType::Unique: os << "&mut "; break;
- case ::HIR::BorrowType::Owned: os << "&move "; break;
+ case ::HIR::BorrowType::Shared: os << ""; break;
+ case ::HIR::BorrowType::Unique: os << "mut "; break;
+ case ::HIR::BorrowType::Owned: os << "move "; break;
}
this->print_type(os, *e.inner);
),
@@ -302,6 +305,8 @@ void HMTypeInferrence::print_type(::std::ostream& os, const ::HIR::TypeRef& tr)
os << "+" << marker.m_path;
this->print_pathparams(os, marker.m_params);
}
+ if( e.m_lifetime != ::HIR::LifetimeRef::new_static() )
+ os << "+ '" << e.m_lifetime;
os << ")";
),
(ErasedType,
@@ -312,8 +317,8 @@ void HMTypeInferrence::print_type(::std::ostream& os, const ::HIR::TypeRef& tr)
os << "+";
os << tr;
}
- if( e.m_lifetime.name != "" )
- os << "+ '" << e.m_lifetime.name;
+ if( e.m_lifetime != ::HIR::LifetimeRef::new_static() )
+ os << "+ '" << e.m_lifetime;
os << "/*" << e.m_origin << "*/";
),
(Tuple,
diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp
index 335875a5..58688d6e 100644
--- a/src/hir_typeck/helpers.hpp
+++ b/src/hir_typeck/helpers.hpp
@@ -187,7 +187,7 @@ public:
/// Expand any located associated types in the input, operating in-place and returning the result
::HIR::TypeRef expand_associated_types(const Span& sp, ::HIR::TypeRef input) const {
expand_associated_types_inplace(sp, input, LList<const ::HIR::TypeRef*>());
- return mv$(input);
+ return input;
}
const ::HIR::TypeRef& expand_associated_types(const Span& sp, const ::HIR::TypeRef& input, ::HIR::TypeRef& tmp) const {
diff --git a/src/include/debug.hpp b/src/include/debug.hpp
index 2f593cfb..3f059301 100644
--- a/src/include/debug.hpp
+++ b/src/include/debug.hpp
@@ -1,4 +1,11 @@
/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * include/debug.hpp
+ * - Common compiler debugging macros/helpers
+ *
+ * see also src/include/span.hpp
*/
#pragma once
#include <sstream>
diff --git a/src/include/serialise.hpp b/src/include/serialise.hpp
deleted file mode 100644
index 0d6d781a..00000000
--- a/src/include/serialise.hpp
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- */
-#ifndef _SERIALSE_HPP_INCLUDED_
-#define _SERIALSE_HPP_INCLUDED_
-
-#include <vector>
-#include <string>
-#include <map>
-#include <memory>
-#include <stdexcept>
-
-class Serialiser;
-class Deserialiser;
-
-#define SERIALISABLE_PROTOTYPES()\
- const char* serialise_tag() const override; \
- void serialise(::Serialiser& s) const override; \
- void deserialise(::Deserialiser& s) override
-#define SERIALISE_TYPE(method_prefix, tag_str, body, des_body) \
- const char* method_prefix serialise_tag() const { return tag_str; } \
- void method_prefix serialise(::Serialiser& s) const { body } \
- void method_prefix deserialise(::Deserialiser& s) { des_body }
-#define SERIALISE_TYPE_A(method_prefix, tag_str, body) SERIALISE_TYPE(method_prefix, tag_str, body, body)
-#define SERIALISE_TYPE_S(class_, body) SERIALISE_TYPE(class_::, #class_, body, body)
-#define SERIALISE_TU(class_, tag_str, val_name, ...) SERIALISE_TYPE(class_::, tag_str,\
- {\
- s << class_::tag_to_str(this->tag());\
- TU_MATCH(class_, (*this), (val_name), __VA_ARGS__)\
- },/*
-*/ {\
- ::std::string STU_tag_str;\
- s.item(STU_tag_str);\
- auto tag = class_::tag_from_str(STU_tag_str);\
- switch(tag) { \
- case class_::TAGDEAD: break;\
- SERIALISE_TU_MATCH_ARMS(class_, val_name, __VA_ARGS__)\
- }\
- })
-#define SERIALISE_TU_MATCH_ARM(CLASS, VAL_NAME, TAG, ...) case CLASS::TAG_##TAG: {/*
-*/ *this = CLASS::make_##TAG({});/*
-*/ auto& VAL_NAME = this->as_##TAG(); /*
-*/ __VA_ARGS__/*
-*/} break;
-#define SERIALISE_TU_MATCH_ARMS(CLASS, NAME, ...) TU_EXP1( TU_GMA(__VA_ARGS__)(SERIALISE_TU_MATCH_ARM, (CLASS, NAME), __VA_ARGS__) )
-
-class DeserialiseFailure:
- public ::std::runtime_error
-{
- //const char *m_fcn;
- //const char *m_message;
-public:
- DeserialiseFailure(const char *fcn, const char *message):
- ::std::runtime_error("Deserialise failure")//,
- //m_fcn(fcn),
- //m_message(message)
- {}
-};
-
-class Serialisable
-{
-public:
- virtual const char* serialise_tag() const = 0;
- virtual void serialise(Serialiser& s) const = 0;
- virtual void deserialise(Deserialiser& s) = 0;
-};
-
-class Serialiser
-{
-protected:
- virtual void start_object(const char *tag) = 0;
- virtual void end_object(const char *tag) = 0;
- virtual void start_array(unsigned int size) = 0;
- virtual void end_array() = 0;
-public:
- template<typename T>
- inline void item(T& v) { *this << v; }
-
- virtual Serialiser& operator<<(bool val) = 0;
- virtual Serialiser& operator<<(uint64_t val) = 0;
- virtual Serialiser& operator<<(int64_t val) = 0;
- virtual Serialiser& operator<<(double val) = 0;
- Serialiser& operator<<(unsigned int val) { return *this << (uint64_t)val; };
- virtual Serialiser& operator<<(const char* s) = 0;
- Serialiser& operator<<(const ::std::string& s) {
- return *this << s.c_str();
- }
- Serialiser& operator<<(const Serialisable& subobj);
-
- template<typename T>
- Serialiser& operator<<(const ::std::vector<T>& v)
- {
- start_array(v.size());
- for(const auto& ent : v)
- *this << ent;
- end_array();
- return *this;
- }
- template<typename T>
- Serialiser& operator<<(const ::std::shared_ptr<T>& v)
- {
- *this << v.get();
- if(v.get())
- *this << *v;
- return *this;
- }
- template<typename T>
- Serialiser& operator<<(const ::std::unique_ptr<T>& v)
- {
- *this << v.get();
- if(v.get())
- *this << *v;
- return *this;
- }
- template<typename T1, typename T2>
- Serialiser& operator<<(const ::std::pair<T1,T2>& v)
- {
- start_array(2);
- *this << v.first;
- *this << v.second;
- end_array();
- return *this;
- }
- template<typename T1, typename T2>
- Serialiser& operator<<(const ::std::map<T1,T2>& v)
- {
- start_array(v.size());
- for(const auto& ent : v)
- *this << ent;
- end_array();
- return *this;
- }
-};
-
-class Deserialiser
-{
-protected:
- virtual size_t start_array() = 0;
- virtual void end_array() = 0;
-
- virtual ::std::string read_tag() = 0;
-public:
- virtual void item(bool& b) = 0;
- virtual void item(uint64_t& v) = 0;
- void item(unsigned int& v) { uint64_t v1; this->item(v1); v = static_cast<unsigned int>(v1); }
- virtual void item(int64_t& val) = 0;
- virtual void item(double& v) = 0;
- virtual void item(::std::string& s) = 0;
-
- virtual void start_object(const char *tag) = 0;
- virtual void end_object(const char *tag) = 0;
- ::std::string start_object();
-
- void item(Serialisable& v);
- Deserialiser& operator>>(Serialisable& v) {
- this->item(v);
- return *this;
- }
-
- template<typename T>
- void item(::std::vector<T>& v) {
- size_t size = start_array();
- v.reserve(size);
- for(size_t i = 0; i < size; i ++) {
- T item;
- this->item(item);
- v.emplace_back( ::std::move(item) );
- }
- end_array();
- }
- template<typename T>
- void item(::std::shared_ptr<T>& v)
- {
- bool present;
-
- item(present);
-
- if(present) {
- v.reset(new T);
- item(*v);
- }
- else {
- v.reset();
- }
- }
- template<typename T>
- void item(::std::unique_ptr<T>& v)
- {
- bool present;
-
- item(present);
-
- if(present) {
- v.reset( T::from_deserialiser(*this).release() );
- }
- else {
- v.reset();
- }
- }
- template<typename T1, typename T2>
- void item(::std::pair<T1,T2>& v)
- {
- if(2 != start_array())
- throw ::std::runtime_error("Invalid array size for pair");
- item(v.first);
- item(v.second);
- end_array();
- }
- template<typename T1, typename T2>
- void item(::std::map<T1,T2>& v)
- {
- size_t count = start_array();
- while(count--) {
- ::std::pair<T1,T2> e;
- item(e);
- v.insert( ::std::move(e) );
- }
- end_array();
- }
-};
-
-#endif
-
diff --git a/src/include/serialiser_texttree.hpp b/src/include/serialiser_texttree.hpp
deleted file mode 100644
index 7c86d326..00000000
--- a/src/include/serialiser_texttree.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- */
-
-#ifndef _SERIALISER_TEXTTREE_HPP_INCLUDED_
-#define _SERIALISER_TEXTTREE_HPP_INCLUDED_
-
-#include <ostream>
-#include <istream>
-#include "serialise.hpp"
-
-class Serialiser_TextTree:
- public Serialiser
-{
- ::std::ostream& m_os;
- int m_indent_level;
- bool m_array_was_empty;
-public:
- Serialiser_TextTree(::std::ostream& os);
-
- virtual Serialiser& operator<<(bool val) override;
- virtual Serialiser& operator<<(uint64_t val) override;
- virtual Serialiser& operator<<(int64_t val) override;
- virtual Serialiser& operator<<(double val) override;
- virtual Serialiser& operator<<(const char* s) override;
-
-protected:
- virtual void start_object(const char *tag) override;
- virtual void end_object(const char* tag) override;
- virtual void start_array(unsigned int size) override;
- virtual void end_array() override;
-private:
- void indent();
- void unindent();
- void print_indent();
-};
-
-
-class Deserialiser_TextTree:
- public Deserialiser
-{
- ::std::istream& m_is;
-
- static bool is_ws(char c);
- char getc();
- char peekc();
- void eat_ws();
-public:
- Deserialiser_TextTree(::std::istream& is);
-
-protected:
- virtual size_t start_array() override;
- virtual void end_array() override;
- virtual ::std::string read_tag() override;
-
-public:
- virtual void item(bool& b) override;
- virtual void item(uint64_t& v) override;
- virtual void item(int64_t& v) override;
- virtual void item(double& v) override;
- virtual void item(::std::string& s) override;
-
- virtual void start_object(const char *tag) override;
- virtual void end_object(const char *tag) override;
-};
-
-#endif
-
diff --git a/src/include/span.hpp b/src/include/span.hpp
index 59c960fc..68d6bfdf 100644
--- a/src/include/span.hpp
+++ b/src/include/span.hpp
@@ -74,4 +74,4 @@ Spanned<T> make_spanned(Span sp, T val) {
#define BUG(span, msg) do { ::Span(span).bug([&](::std::ostream& os) { os << __FILE__ << ":" << __LINE__ << ": " << msg; }); throw ::std::runtime_error("Bug fell through"); } while(0)
#define TODO(span, msg) do { const char* __TODO_func = __func__; ::Span(span).bug([&](::std::ostream& os) { os << __FILE__ << ":" << __LINE__ << ": TODO: " << __TODO_func << " - " << msg; }); throw ::std::runtime_error("Bug (todo) fell through"); } while(0)
-#define ASSERT_BUG(span, cnd, msg) do { if( !(cnd) ) { ::Span(span).bug([&](::std::ostream& os) { os << "ASSERT FAIL: " #cnd << ": " << msg; }); throw ::std::runtime_error("Bug fell through"); } } while(0)
+#define ASSERT_BUG(span, cnd, msg) do { if( !(cnd) ) { ::Span(span).bug([&](::std::ostream& os) { os << "ASSERT FAIL: " << __FILE__ << ":" << __LINE__ << ":" #cnd << ": " << msg; }); throw ::std::runtime_error("Bug fell through"); } } while(0)
diff --git a/src/include/string_view.hpp b/src/include/string_view.hpp
new file mode 100644
index 00000000..7d049e9e
--- /dev/null
+++ b/src/include/string_view.hpp
@@ -0,0 +1,89 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * include/string_view.hpp
+ * - Clone of the `string_view` class (introduced in C++17)
+ */
+#pragma once
+#include <string>
+#include <cstddef> // size_t
+#include <iostream> // ostream
+
+namespace std {
+
+class string_view
+{
+ const char* m_start;
+ const char* m_end;
+
+public:
+ string_view():
+ m_start(nullptr), m_end(nullptr)
+ {
+ }
+ string_view(const char* s, const char* e):
+ m_start(s), m_end(e)
+ {
+ if(!(s <= e))
+ throw ::std::invalid_argument("start must be before end for string_view");
+ }
+ string_view(const char* s):
+ m_start(s), m_end(s)
+ {
+ while(*m_end)
+ m_end ++;
+ }
+ string_view(const string& s):
+ m_start(s.data()), m_end(m_start + s.size())
+ {
+ }
+
+ size_t size() const {
+ return m_end - m_start;
+ }
+
+ bool operator==(const string_view& x) const { return cmp(x) == 0; }
+ bool operator!=(const string_view& x) const { return cmp(x) != 0; }
+ bool operator< (const string_view& x) const { return cmp(x) < 0; }
+ bool operator> (const string_view& x) const { return cmp(x) > 0; }
+ bool operator<=(const string_view& x) const { return cmp(x) <= 0; }
+ bool operator>=(const string_view& x) const { return cmp(x) >= 0; }
+ bool operator==(const char* x) const { return cmp(string_view(x)) == 0; }
+ bool operator!=(const char* x) const { return cmp(string_view(x)) != 0; }
+ bool operator< (const char* x) const { return cmp(string_view(x)) < 0; }
+ bool operator> (const char* x) const { return cmp(string_view(x)) > 0; }
+ bool operator<=(const char* x) const { return cmp(string_view(x)) <= 0; }
+ bool operator>=(const char* x) const { return cmp(string_view(x)) >= 0; }
+ bool operator==(const string& x) const { return cmp(string_view(x)) == 0; }
+ bool operator!=(const string& x) const { return cmp(string_view(x)) != 0; }
+ bool operator< (const string& x) const { return cmp(string_view(x)) < 0; }
+ bool operator> (const string& x) const { return cmp(string_view(x)) > 0; }
+ bool operator<=(const string& x) const { return cmp(string_view(x)) <= 0; }
+ bool operator>=(const string& x) const { return cmp(string_view(x)) >= 0; }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const string_view& x) {
+ for(const char* s = x.m_start; s != x.m_end; s++)
+ os << *s;
+ return os;
+ }
+
+private:
+ int cmp(const string_view& x) const {
+ const char *a, *b;
+ for( a = m_start, b = x.m_start; a != m_end && b != x.m_end; a++, b++)
+ {
+ if( *a != *b ) {
+ return *a < *b ? -1 : 1;
+ }
+ }
+ if( a == m_end && b == m_end )
+ return 0;
+ if( a == m_end )
+ return -1;
+ else
+ return 1;
+ }
+};
+
+}
diff --git a/src/include/synext_decorator.hpp b/src/include/synext_decorator.hpp
index af19491d..049a28b0 100644
--- a/src/include/synext_decorator.hpp
+++ b/src/include/synext_decorator.hpp
@@ -13,7 +13,7 @@
class TypeRef;
namespace AST {
class Crate;
- class MetaItem;
+ class Attribute;
class Path;
struct StructItem;
@@ -38,26 +38,26 @@ enum class AttrStage
class ExpandDecorator
{
- void unexpected(const Span& sp, const AST::MetaItem& mi, const char* loc_str) const;
+ void unexpected(const Span& sp, const AST::Attribute& mi, const char* loc_str) const;
public:
virtual AttrStage stage() const = 0;
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const { unexpected(sp, mi, "crate"); }
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const { unexpected(sp, mi, "item"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const { unexpected(sp, mi, "crate"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const { unexpected(sp, mi, "item"); }
// NOTE: To delete, set the type to `_`
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const { unexpected(sp, mi, "impl"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const { unexpected(sp, mi, "impl"); }
// NOTE: To delete, clear the name
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::StructItem& si) const { unexpected(sp, mi, "struct item"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::AST::StructItem& si) const { unexpected(sp, mi, "struct item"); }
// NOTE: To delete, make the type invalid
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::TupleItem& si) const { unexpected(sp, mi, "tuple item"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::AST::TupleItem& si) const { unexpected(sp, mi, "tuple item"); }
// NOTE: To delete, clear the name
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::EnumVariant& ev) const { unexpected(sp, mi, "enum variant"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::AST::EnumVariant& ev) const { unexpected(sp, mi, "enum variant"); }
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::std::unique_ptr<AST::ExprNode>& expr) const { unexpected(sp, mi, "expression"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::std::unique_ptr<AST::ExprNode>& expr) const { unexpected(sp, mi, "expression"); }
// NOTE: To delete, clear the patterns vector
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::ExprNode_Match_Arm& expr) const { unexpected(sp, mi, "match arm"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::AST::ExprNode_Match_Arm& expr) const { unexpected(sp, mi, "match arm"); }
// NOTE: To delete, clear the value
- virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::ExprNode_StructLiteral::Ent& expr) const { unexpected(sp, mi, "struct literal ent"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::AST::ExprNode_StructLiteral::Ent& expr) const { unexpected(sp, mi, "struct literal ent"); }
};
struct DecoratorDef;
diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp
index 9372fa6e..a393ba46 100644
--- a/src/macro_rules/eval.cpp
+++ b/src/macro_rules/eval.cpp
@@ -712,15 +712,16 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type
case MacroPatEnt::PAT_ITEM: {
assert( lex.parse_state().module );
const auto& cur_mod = *lex.parse_state().module;
- return InterpolatedFragment( Parse_Mod_Item_S(lex, cur_mod.m_file_info, cur_mod.path(), AST::MetaItems{}) );
+ return InterpolatedFragment( Parse_Mod_Item_S(lex, cur_mod.m_file_info, cur_mod.path(), AST::AttributeList{}) );
} break;
case MacroPatEnt::PAT_IDENT:
- // TODO: Any reserved word is also valid as an ident
+ // NOTE: Any reserved word is also valid as an ident
GET_TOK(tok, lex);
if( tok.type() == TOK_IDENT || is_reserved_word(tok.type()) )
;
else
CHECK_TOK(tok, TOK_IDENT);
+ // TODO: TOK_INTERPOLATED_IDENT
return InterpolatedFragment( TokenTree(lex.getHygiene(), tok) );
}
throw "";
diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp
index 2a588a78..c04e3548 100644
--- a/src/macro_rules/macro_rules.hpp
+++ b/src/macro_rules/macro_rules.hpp
@@ -19,7 +19,7 @@
class MacroExpander;
-TAGGED_UNION_EX(MacroExpansionEnt, (: public Serialisable), Token, (
+TAGGED_UNION(MacroExpansionEnt, Token,
// TODO: have a "raw" stream instead of just tokens
(Token, Token),
// TODO: Have a flag on `NamedValue` that indicates that it is the only/last usage of this particular value (at this level)
@@ -34,19 +34,11 @@ TAGGED_UNION_EX(MacroExpansionEnt, (: public Serialisable), Token, (
/// Boolean is true if the variable will be unconditionally expanded
::std::map< unsigned int, bool> variables;
})
- ),
- (),
- (),
- (
- public:
- SERIALISABLE_PROTOTYPES();
- )
);
extern ::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x);
/// Matching pattern entry
-struct MacroPatEnt:
- public Serialisable
+struct MacroPatEnt
{
::std::string name;
unsigned int name_index = 0;
@@ -99,13 +91,10 @@ struct MacroPatEnt:
friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt& x);
friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt::Type& x);
-
- SERIALISABLE_PROTOTYPES();
};
/// An expansion arm within a macro_rules! blcok
-struct MacroRulesArm:
- public Serialisable
+struct MacroRulesArm
{
/// Names for the parameters
::std::vector< ::std::string> m_param_names;
@@ -126,13 +115,10 @@ struct MacroRulesArm:
MacroRulesArm& operator=(const MacroRulesArm&) = delete;
MacroRulesArm(MacroRulesArm&&) = default;
MacroRulesArm& operator=(MacroRulesArm&&) = default;
-
- SERIALISABLE_PROTOTYPES();
};
/// A sigle 'macro_rules!' block
-class MacroRules:
- public Serialisable
+class MacroRules
{
public:
/// Marks if this macro should be exported from the defining crate
@@ -152,8 +138,6 @@ public:
}
virtual ~MacroRules();
MacroRules(MacroRules&&) = default;
-
- SERIALISABLE_PROTOTYPES();
};
extern ::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod);
diff --git a/src/macro_rules/mod.cpp b/src/macro_rules/mod.cpp
index 0f16a377..2613a0b4 100644
--- a/src/macro_rules/mod.cpp
+++ b/src/macro_rules/mod.cpp
@@ -161,55 +161,6 @@ MacroRulesPtr::~MacroRulesPtr()
}
}
-SERIALISE_TYPE_S(MacroRulesArm, {
-})
-
-void operator%(Serialiser& s, MacroPatEnt::Type c) {
- switch(c) {
- #define _(v) case MacroPatEnt::v: s << #v; return
- _(PAT_TOKEN);
- _(PAT_TT);
- _(PAT_PAT);
- _(PAT_TYPE);
- _(PAT_EXPR);
- _(PAT_LOOP);
- _(PAT_STMT);
- _(PAT_PATH);
- _(PAT_BLOCK);
- _(PAT_META);
- _(PAT_ITEM);
- _(PAT_IDENT);
- #undef _
- }
-}
-void operator%(::Deserialiser& s, MacroPatEnt::Type& c) {
- ::std::string n;
- s.item(n);
- #define _(v) else if(n == #v) c = MacroPatEnt::v
- if(0) ;
- _(PAT_TOKEN);
- _(PAT_TT);
- _(PAT_PAT);
- _(PAT_TYPE);
- _(PAT_EXPR);
- _(PAT_LOOP);
- //_(PAT_OPTLOOP);
- _(PAT_STMT);
- _(PAT_PATH);
- _(PAT_BLOCK);
- _(PAT_META);
- _(PAT_IDENT);
- _(PAT_ITEM);
- else
- throw ::std::runtime_error( FMT("No conversion for '" << n << "'") );
- #undef _
-}
-SERIALISE_TYPE_S(MacroPatEnt, {
- s % type;
- s.item(name);
- s.item(tok);
- s.item(subpats);
-});
::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt& x)
{
switch(x.type)
@@ -257,20 +208,6 @@ SERIALISE_TYPE_S(MacroPatEnt, {
return os;
}
-SERIALISE_TU(MacroExpansionEnt, "MacroExpansionEnt", e,
-(Token,
- s.item(e);
- ),
-(NamedValue,
- s.item(e);
- ),
-(Loop,
- s.item(e.entries);
- s.item(e.joiner);
- //s.item(e.variables);
- )
-);
-
::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x)
{
TU_MATCH( MacroExpansionEnt, (x), (e),
@@ -295,8 +232,4 @@ SERIALISE_TU(MacroExpansionEnt, "MacroExpansionEnt", e,
MacroRules::~MacroRules()
{
}
-SERIALISE_TYPE_S(MacroRules, {
- s.item( m_exported );
- s.item( m_rules );
-});
diff --git a/src/main.cpp b/src/main.cpp
index 212cdfd3..358de95e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -9,11 +9,11 @@
#include <iomanip>
#include <string>
#include <set>
+#include <string_view.hpp>
#include "parse/lex.hpp"
#include "parse/parseerror.hpp"
#include "ast/ast.hpp"
#include "ast/crate.hpp"
-#include <serialiser_texttree.hpp>
#include <cstring>
#include <main_bindings.hpp>
#include "resolve/main_bindings.hpp"
@@ -26,51 +26,7 @@
#include "trans/target.hpp"
#include "expand/cfg.hpp"
-
-// Hacky default target
-#ifdef _MSC_VER
-# if defined(_WIN64)
-# define DEFAULT_TARGET_NAME "x86_64-windows-msvc"
-# else
-# define DEFAULT_TARGET_NAME "x86-windows-msvc"
-# endif
-#elif defined(__linux__)
-# if defined(__amd64__)
-# define DEFAULT_TARGET_NAME "x86_64-linux-gnu"
-# elif defined(__aarch64__)
-# define DEFAULT_TARGET_NAME "aarch64-linux-gnu"
-# elif defined(__arm__)
-# define DEFAULT_TARGET_NAME "arm-linux-gnu"
-# elif defined(__i386__)
-# define DEFAULT_TARGET_NAME "i586-linux-gnu"
-# else
-# error "Unable to detect a suitable default target (linux-gnu)"
-# endif
-#elif defined(__MINGW32__)
-# if defined(_WIN64)
-# define DEFAULT_TARGET_NAME "x86_64-windows-gnu"
-# else
-# define DEFAULT_TARGET_NAME "i586-windows-gnu"
-# endif
-#elif defined(__NetBSD__)
-# if defined(__amd64__)
-# define DEFAULT_TARGET_NAME "x86_64-unknown-netbsd"
-# endif
-#elif defined(__OpenBSD__)
-# if defined(__amd64__)
-# define DEFAULT_TARGET_NAME "x86_64-unknown-openbsd"
-# elif defined(__aarch64__)
-# define DEFAULT_TARGET_NAME "aarch64-unknown-openbsd"
-# elif defined(__arm__)
-# define DEFAULT_TARGET_NAME "arm-unknown-openbsd"
-# elif defined(__i386__)
-# define DEFAULT_TARGET_NAME "i686-unknown-openbsd"
-# else
-# error "Unable to detect a suitable default target (OpenBSD)"
-# endif
-#else
-# error "Unable to detect a suitable default target"
-#endif
+#include <target_detect.h> // tools/common/target_detect.h
int g_debug_indent_level = 0;
bool g_debug_enabled = true;
@@ -201,6 +157,10 @@ struct ProgramParams
bool disable_mir_optimisations = false;
bool full_validate = false;
bool full_validate_early = false;
+
+ bool dump_ast = false;
+ bool dump_hir = false;
+ bool dump_mir = false;
} debug;
struct {
::std::string codegen_type;
@@ -356,10 +316,12 @@ int main(int argc, char *argv[])
DEBUG("params.outfile = " << params.outfile);
}
- // XXX: Dump crate before resolve
- CompilePhaseV("Dump Expanded", [&]() {
- Dump_Rust( FMT(params.outfile << "_0a_exp.rs").c_str(), crate );
- });
+ if( params.debug.dump_ast )
+ {
+ CompilePhaseV("Dump Expanded", [&]() {
+ Dump_Rust( FMT(params.outfile << "_1_ast.rs").c_str(), crate );
+ });
+ }
if( params.last_stage == ProgramParams::STAGE_EXPAND ) {
return 0;
@@ -467,10 +429,12 @@ int main(int argc, char *argv[])
Resolve_Absolutise(crate); // - Convert all paths to Absolute or UFCS, and resolve variables
});
- // XXX: Dump crate before HIR
- CompilePhaseV("Temp output - Resolved", [&]() {
- Dump_Rust( FMT(params.outfile << "_1_res.rs").c_str(), crate );
- });
+ if( params.debug.dump_ast )
+ {
+ CompilePhaseV("Temp output - Resolved", [&]() {
+ Dump_Rust( FMT(params.outfile << "_1_ast.rs").c_str(), crate );
+ });
+ }
if( params.last_stage == ProgramParams::STAGE_RESOLVE ) {
return 0;
@@ -508,10 +472,14 @@ int main(int argc, char *argv[])
ConvertHIR_ConstantEvaluate(*hir_crate);
});
- CompilePhaseV("Dump HIR", [&]() {
- ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
- HIR_Dump( os, *hir_crate );
- });
+ if( params.debug.dump_hir )
+ {
+ // DUMP after initial consteval
+ CompilePhaseV("Dump HIR", [&]() {
+ ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
+ HIR_Dump( os, *hir_crate );
+ });
+ }
// === Type checking ===
// - This can recurse and call the MIR lower to evaluate constants
@@ -546,10 +514,14 @@ int main(int argc, char *argv[])
CompilePhaseV("Expand HIR ErasedType", [&]() {
HIR_Expand_ErasedType(*hir_crate);
});
- CompilePhaseV("Dump HIR", [&]() {
- ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
- HIR_Dump( os, *hir_crate );
- });
+ if( params.debug.dump_hir )
+ {
+ // DUMP after typecheck (before validation)
+ CompilePhaseV("Dump HIR", [&]() {
+ ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
+ HIR_Dump( os, *hir_crate );
+ });
+ }
// - Ensure that typeck worked (including Fn trait call insertion etc)
CompilePhaseV("Typecheck Expressions (validate)", [&]() {
Typecheck_Expressions_Validate(*hir_crate);
@@ -564,10 +536,14 @@ int main(int argc, char *argv[])
HIR_GenerateMIR(*hir_crate);
});
- CompilePhaseV("Dump MIR", [&]() {
- ::std::ofstream os (FMT(params.outfile << "_3_mir.rs"));
- MIR_Dump( os, *hir_crate );
- });
+ if( params.debug.dump_mir )
+ {
+ // DUMP after generation
+ CompilePhaseV("Dump MIR", [&]() {
+ ::std::ofstream os (FMT(params.outfile << "_3_mir.rs"));
+ MIR_Dump( os, *hir_crate );
+ });
+ }
// Validate the MIR
CompilePhaseV("MIR Validate", [&]() {
@@ -578,10 +554,15 @@ int main(int argc, char *argv[])
CompilePhaseV("Constant Evaluate Full", [&]() {
ConvertHIR_ConstantEvaluateFull(*hir_crate);
});
- CompilePhaseV("Dump HIR", [&]() {
- ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
- HIR_Dump( os, *hir_crate );
- });
+
+ if( params.debug.dump_hir )
+ {
+ // DUMP after consteval (full HIR again)
+ CompilePhaseV("Dump HIR", [&]() {
+ ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
+ HIR_Dump( os, *hir_crate );
+ });
+ }
// - Expand constants in HIR and virtualise calls
CompilePhaseV("MIR Cleanup", [&]() {
@@ -599,10 +580,14 @@ int main(int argc, char *argv[])
MIR_OptimiseCrate(*hir_crate, params.debug.disable_mir_optimisations);
});
- CompilePhaseV("Dump MIR", [&]() {
- ::std::ofstream os (FMT(params.outfile << "_3_mir.rs"));
- MIR_Dump( os, *hir_crate );
- });
+ if( params.debug.dump_mir )
+ {
+ // DUMP: After optimisation
+ CompilePhaseV("Dump MIR", [&]() {
+ ::std::ofstream os (FMT(params.outfile << "_3_mir.rs"));
+ MIR_Dump( os, *hir_crate );
+ });
+ }
CompilePhaseV("MIR Validate PO", [&]() {
MIR_CheckCrate(*hir_crate);
});
@@ -640,72 +625,83 @@ int main(int argc, char *argv[])
// If the test harness is enabled, override crate type to "Executable"
crate_type = ::AST::Crate::Type::Executable;
}
- switch( crate_type )
+
+ // Enumerate items to be passed to codegen
+ TransList items = CompilePhase<TransList>("Trans Enumerate", [&]() {
+ switch( crate_type )
+ {
+ case ::AST::Crate::Type::Unknown:
+ ::std::cerr << "BUG? Unknown crate type" << ::std::endl;
+ exit(1);
+ break;
+ case ::AST::Crate::Type::RustLib:
+ case ::AST::Crate::Type::RustDylib:
+ case ::AST::Crate::Type::CDylib:
+ return Trans_Enumerate_Public(*hir_crate);
+ case ::AST::Crate::Type::ProcMacro:
+ // TODO: proc macros enumerate twice, once as a library (why?) and again as an executable
+ return Trans_Enumerate_Public(*hir_crate);
+ case ::AST::Crate::Type::Executable:
+ return Trans_Enumerate_Main(*hir_crate);
+ }
+ throw ::std::runtime_error("Invalid crate_type value");
+ });
+ // - Generate monomorphised versions of all functions
+ CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items); });
+ // - Do post-monomorph inlining
+ CompilePhaseV("MIR Optimise Inline", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items); });
+ // - Clean up no-unused functions
+ //CompilePhaseV("Trans Enumerate Cleanup", [&]() { Trans_Enumerate_Cleanup(*hir_crate, items); });
+
+ switch(crate_type)
{
case ::AST::Crate::Type::Unknown:
- // ERROR?
- break;
- case ::AST::Crate::Type::RustLib: {
- #if 1
- // Generate a .o
- TransList items = CompilePhase<TransList>("Trans Enumerate", [&]() { return Trans_Enumerate_Public(*hir_crate); });
- CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items); });
- CompilePhaseV("MIR Optimise Inline", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items); });
- //CompilePhaseV("Trans Enumerate Cleanup", [&]() { Trans_Enumerate_Cleanup(*hir_crate, items); });
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, false); });
- #endif
-
+ throw "";
+ case ::AST::Crate::Type::RustLib:
+ // Generate a loadable .o
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); });
// Save a loadable HIR dump
- CompilePhaseV("HIR Serialise", [&]() {
- //HIR_Serialise(params.outfile + ".meta", *hir_crate);
- HIR_Serialise(params.outfile, *hir_crate);
- });
-
- // Link metatdata and object into a .rlib
- break; }
- case ::AST::Crate::Type::RustDylib: {
- #if 1
- // Generate a .o
- TransList items = CompilePhase<TransList>("Trans Enumerate", [&]() { return Trans_Enumerate_Public(*hir_crate); });
- CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items); });
- CompilePhaseV("MIR Optimise Inline", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items); });
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, false); });
- #endif
+ CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); });
+ // TODO: Link metatdata and object into a .rlib
+ //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::StaticLibrary);
+ break;
+ case ::AST::Crate::Type::RustDylib:
+ // Generate a .so
+ //CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".so", trans_opt, *hir_crate, items, CodegenOutput::DynamicLibrary); });
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); });
// Save a loadable HIR dump
CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); });
-
- // Generate a .so/.dll
- // TODO: Codegen and include the metadata in a non-loadable segment
- break; }
+ // TODO: Add the metadata to the .so as a non-loadable segment
+ //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::DynamicLibrary);
+ break;
case ::AST::Crate::Type::CDylib:
// Generate a .so/.dll
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, trans_opt, *hir_crate, items, /*is_executable=*/false); });
+ // - No metadata file
+ //Trans_Link(params.outfile, "", params.outfile + ".o", CodegenOutput::DynamicLibrary);
break;
case ::AST::Crate::Type::ProcMacro: {
// Needs: An executable (the actual macro handler), metadata (for `extern crate foo;`)
- // Can just emit the metadata and do miri?
- // - Requires MIR for EVERYTHING, not feasable.
- TransList items = CompilePhase<TransList>("Trans Enumerate", [&]() { return Trans_Enumerate_Public(*hir_crate); });
- CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items); });
- CompilePhaseV("MIR Optimise Inline", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items); });
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, false); });
+ // 1. Generate code for the .o file
+ // TODO: Is the .o actually needed for proc macros?
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); });
+
+ // 2. Generate code for the plugin itself
TransList items2 = CompilePhase<TransList>("Trans Enumerate", [&]() { return Trans_Enumerate_Main(*hir_crate); });
CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items2); });
CompilePhaseV("MIR Optimise Inline", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items2); });
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + "-plugin", trans_opt, *hir_crate, items2, true); });
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + "-plugin", trans_opt, *hir_crate, items2, /*is_executable=*/true); });
- hir_crate->m_lang_items.clear(); // Make sure that we're not exporting any lang items
+ // - Save a very basic HIR dump, making sure that there's no lang items in it (e.g. `mrustc-main`)
+ hir_crate->m_lang_items.clear();
CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); });
+ //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::StaticLibrary);
+ //Trans_Link(params.outfile+"-plugin", "", params.outfile + "-plugin.o", CodegenOutput::StaticLibrary);
break; }
case ::AST::Crate::Type::Executable:
- // Generate a binary
- // - Enumerate items for translation
- TransList items = CompilePhase<TransList>("Trans Enumerate", [&]() { return Trans_Enumerate_Main(*hir_crate); });
- // - Monomorphise
- CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items); });
- CompilePhaseV("MIR Optimise Inline", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items); });
- // - Perform codegen
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, trans_opt, *hir_crate, items, true); });
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, trans_opt, *hir_crate, items, /*is_executable=*/true); });
+ //Trans_Link(params.outfile, "", params.outfile + ".o", CodegenOutput::Executable);
break;
}
}
@@ -869,6 +865,18 @@ ProgramParams::ProgramParams(int argc, char *argv[])
no_optval();
this->debug.full_validate_early = true;
}
+ else if( optname == "dump-ast" ) {
+ no_optval();
+ this->debug.dump_ast = true;
+ }
+ else if( optname == "dump-hir" ) {
+ no_optval();
+ this->debug.dump_hir = true;
+ }
+ else if( optname == "dump-mir" ) {
+ no_optval();
+ this->debug.dump_mir = true;
+ }
else if( optname == "stop-after" ) {
get_optval();
if( optval == "parse" )
@@ -877,10 +885,10 @@ ProgramParams::ProgramParams(int argc, char *argv[])
this->last_stage = STAGE_EXPAND;
else if( optval == "resolve" )
this->last_stage = STAGE_RESOLVE;
+ else if( optval == "typeck" )
+ this->last_stage = STAGE_TYPECK;
else if( optval == "mir" )
this->last_stage = STAGE_MIR;
- else if( optval == "ALL" )
- this->last_stage = STAGE_ALL;
else {
::std::cerr << "Unknown argument to -Z stop-after - '" << optval << "'" << ::std::endl;
exit(1);
@@ -1053,6 +1061,42 @@ ProgramParams::ProgramParams(int argc, char *argv[])
::std::cerr << "No input file passed" << ::std::endl;
exit(1);
}
+
+ if( const auto* a = getenv("MRUSTC_DUMP") )
+ {
+ while( a[0] )
+ {
+ const char* end = strchr(a, ':');
+
+ ::std::string_view s;
+ if( end ) {
+ s = ::std::string_view { a, end };
+ a = end + 1;
+ }
+ else {
+ end = a + strlen(a);
+ s = ::std::string_view { a, end };
+ a = end;
+ }
+
+ if( s == "" ) {
+ // Ignore
+ }
+ else if( s == "ast" ) {
+ this->debug.dump_ast = true;
+ }
+ else if( s == "hir" ) {
+ this->debug.dump_hir = true;
+ }
+ else if( s == "mir" ) {
+ this->debug.dump_mir = true;
+ }
+ else {
+ ::std::cerr << "Unknown option in $MRUSTC_DUMP '" << s << "'" << ::std::endl;
+ // - No terminate, just warn
+ }
+ }
+ }
}
void ProgramParams::show_help() const
{
diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp
index 019a0796..2d4b3468 100644
--- a/src/mir/cleanup.cpp
+++ b/src/mir/cleanup.cpp
@@ -764,7 +764,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
{
auto ty_d = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_d, false);
- auto new_rval = ::MIR::RValue::make_Cast({ ::MIR::LValue::make_Field({ box$(value.clone()), i }), ty_d.clone() });
+ auto new_rval = ::MIR::RValue::make_Struct({ ty_d.m_data.as_Path().path.m_data.as_Generic().clone(), {} });
auto new_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) );
ents.push_back( mv$(new_lval) );
@@ -794,7 +794,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
{
auto ty_d = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_d, false);
- auto new_rval = ::MIR::RValue::make_Cast({ ::MIR::LValue::make_Field({ box$(value.clone()), i }), ty_d.clone() });
+ auto new_rval = ::MIR::RValue::make_Struct({ ty_d.m_data.as_Path().path.m_data.as_Generic().clone(), {} });
auto new_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) );
ents.push_back( mv$(new_lval) );
@@ -1079,12 +1079,6 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
// TODO Share with the CoerceUnsized handling?
se.src = MIR_Cleanup_CoerceUnsized(state, mutator, e.type, src_ty, mv$(e.val));
)
- // Casts to PhantomData are only valid from PhandomData, and are added by _CoerceUnsized
- else if( state.m_resolve.is_type_phantom_data(e.type) )
- {
- // Leave
- MIR_ASSERT(state, state.m_resolve.is_type_phantom_data(src_ty) != nullptr, "PhandomData can only cast from PhantomData");
- }
// - CoerceUnsized should re-create the inner type if known.
else TU_IFLET( ::HIR::TypeRef::Data, e.type.m_data, Path, te,
TU_IFLET( ::HIR::TypeRef::Data, src_ty.m_data, Path, ste,
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp
index c2b80202..dc3b78a7 100644
--- a/src/mir/from_hir.cpp
+++ b/src/mir/from_hir.cpp
@@ -786,10 +786,10 @@ namespace {
{
DEBUG("- constant condition");
if( cond_lit->m_data.as_Boolean() ) {
- m_builder.end_block( ::MIR::Terminator::make_Goto({ true_branch }) );
+ m_builder.end_block( ::MIR::Terminator::make_Goto( true_branch ) );
}
else {
- m_builder.end_block( ::MIR::Terminator::make_Goto({ false_branch }) );
+ m_builder.end_block( ::MIR::Terminator::make_Goto( false_branch ) );
}
return ;
}
diff --git a/src/mir/main_bindings.hpp b/src/mir/main_bindings.hpp
index 9f160b12..cb4f3232 100644
--- a/src/mir/main_bindings.hpp
+++ b/src/mir/main_bindings.hpp
@@ -11,7 +11,7 @@
namespace HIR {
class Crate;
}
-struct TransList;
+class TransList;
extern void HIR_GenerateMIR(::HIR::Crate& crate);
extern void MIR_Dump(::std::ostream& sink, const ::HIR::Crate& crate);
diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp
index ae1f3120..06a8e3dd 100644
--- a/src/mir/optimise.cpp
+++ b/src/mir/optimise.cpp
@@ -2510,6 +2510,12 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
changed = true;
}
} break;
+ TU_ARM(bb.terminator, Call, te) {
+ for(auto& a : te.args)
+ {
+ check_param(a);
+ }
+ } break;
default:
break;
}
diff --git a/src/parse/common.hpp b/src/parse/common.hpp
index ede08984..49499c86 100644
--- a/src/parse/common.hpp
+++ b/src/parse/common.hpp
@@ -40,17 +40,17 @@ extern ::std::vector<AST::PathNode> Parse_PathNodes(TokenStream& lex, eParsePath
extern AST::PathParams Parse_Path_GenericList(TokenStream& lex);
-extern ::std::vector< ::std::string> Parse_HRB(TokenStream& lex);
-extern AST::MetaItems Parse_ItemAttrs(TokenStream& lex);
-extern void Parse_ParentAttrs(TokenStream& lex, AST::MetaItems& out);
-extern AST::MetaItem Parse_MetaItem(TokenStream& lex);
+extern AST::HigherRankedBounds Parse_HRB(TokenStream& lex);
+extern AST::AttributeList Parse_ItemAttrs(TokenStream& lex);
+extern void Parse_ParentAttrs(TokenStream& lex, AST::AttributeList& out);
+extern AST::Attribute Parse_MetaItem(TokenStream& lex);
extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, ::std::string name, TokenStream& lex);
extern TypeRef Parse_Type(TokenStream& lex, bool allow_trait_list = true);
extern AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable);
extern void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl);
-extern void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items);
-extern ::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::MetaItems meta_items);
+extern void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_items);
+extern ::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::AttributeList meta_items);
extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod);
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index 2ac13728..5194e1d8 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -20,7 +20,7 @@
using AST::ExprNode;
using AST::ExprNodeP;
-// TODO: Use a ProtoSpan
+// TODO: Use a ProtoSpan instead of a point span?
static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){en->set_span(lex.point_span()); return ExprNodeP(en); }
#define NEWNODE(type, ...) mk_exprnodep(lex, new type(__VA_ARGS__))
@@ -66,9 +66,10 @@ ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe/*=false*/)
DEBUG("tok = " << tok);
// NOTE: Doc comments can appear within a function and apply to the function
- ::AST::MetaItems node_attrs;
- Parse_ParentAttrs(lex, node_attrs);
- (void)node_attrs; // TODO: Use these attributes
+ if( lex.parse_state().parent_attrs )
+ {
+ Parse_ParentAttrs(lex, *lex.parse_state().parent_attrs);
+ }
if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE )
break;
@@ -98,7 +99,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST:
{
Token tok;
- AST::MetaItems item_attrs = Parse_ItemAttrs(lex);
+ auto item_attrs = Parse_ItemAttrs(lex);
GET_TOK(tok, lex);
// `union Ident` - contextual keyword
@@ -162,6 +163,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST:
}
else if( item_attrs.m_items.size() > 0 ) {
// TODO: Is this an error? - Attributes on a expression that didn't yeild a node.
+ // - They should have applied to the item that was parsed?
}
else {
}
@@ -584,7 +586,7 @@ ExprNodeP Parse_Expr0(TokenStream& lex)
//TRACE_FUNCTION;
Token tok;
- ::AST::MetaItems expr_attrs = Parse_ItemAttrs(lex);
+ auto expr_attrs = Parse_ItemAttrs(lex);
ExprNodeP rv = Parse_Expr1(lex);
auto op = AST::ExprNode_Assign::NONE;
@@ -740,7 +742,6 @@ ExprNodeP Parse_Expr1_1(TokenStream& lex)
return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE, ::std::move(left), ::std::move(right) );
}
-// TODO: Is this left associative?
LEFTASSOC(Parse_Expr1_2, Parse_Expr1_5,
case TOK_TRIPLE_DOT:
rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) );
@@ -915,8 +916,7 @@ ExprNodeP Parse_ExprFC(TokenStream& lex)
GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
break;
case TOK_DOT:
- // Field access / method call
- // TODO: What about tuple indexing?
+ // Field access / method call / tuple index
switch(GET_TOK(tok, lex))
{
case TOK_IDENT: {
@@ -996,7 +996,7 @@ ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path)
::AST::ExprNode_StructLiteral::t_values items;
while( GET_TOK(tok, lex) == TOK_IDENT || tok.type() == TOK_HASH )
{
- ::AST::MetaItems attrs;
+ ::AST::AttributeList attrs; // Note: Parse_ItemAttrs uses lookahead, so can't use it here.
if( tok.type() == TOK_HASH )
{
PUTBACK(tok, lex);
@@ -1097,7 +1097,7 @@ ExprNodeP Parse_ExprVal(TokenStream& lex)
return tok.take_frag_node();
- // TODO: Return/break/continue/... here?
+ // Return/break/continue/... also parsed here (but recurses back up to actually handle them)
case TOK_RWORD_RETURN:
case TOK_RWORD_CONTINUE:
case TOK_RWORD_BREAK:
@@ -1177,7 +1177,6 @@ ExprNodeP Parse_ExprVal(TokenStream& lex)
return NEWNODE( AST::ExprNode_NamedValue, ::std::move(path) );
}
case TOK_RWORD_MOVE:
- // TODO: Annotate closure as move
GET_TOK(tok, lex);
if(tok.type() == TOK_PIPE)
return Parse_ExprVal_Closure(lex, true);
@@ -1271,7 +1270,9 @@ ExprNodeP Parse_ExprVal(TokenStream& lex)
}
ExprNodeP Parse_ExprMacro(TokenStream& lex, AST::Path path)
{
- ASSERT_BUG(lex.point_span(), path.is_trivial(), "TODO: Support path macros - " << path);
+ if( !path.is_trivial() ) {
+ TODO(lex.point_span(), "Support path macros - " << path);
+ }
Token tok;
::std::string name = path.m_class.is_Local() ? path.m_class.as_Local().name : path.nodes()[0].name();
diff --git a/src/parse/interpolated_fragment.cpp b/src/parse/interpolated_fragment.cpp
index 29a7ab5a..9b7979f3 100644
--- a/src/parse/interpolated_fragment.cpp
+++ b/src/parse/interpolated_fragment.cpp
@@ -21,7 +21,7 @@ InterpolatedFragment::~InterpolatedFragment()
delete reinterpret_cast<AST::ExprNode*>(m_ptr);
break;
case InterpolatedFragment::META:
- delete reinterpret_cast<AST::MetaItem*>(m_ptr);
+ delete reinterpret_cast<AST::Attribute*>(m_ptr);
break;
case InterpolatedFragment::ITEM:
delete reinterpret_cast<AST::Named<AST::Item>*>(m_ptr);
@@ -47,9 +47,9 @@ InterpolatedFragment::InterpolatedFragment(InterpolatedFragment::Type type, AST:
m_ptr( ptr )
{
}
-InterpolatedFragment::InterpolatedFragment(AST::MetaItem v):
+InterpolatedFragment::InterpolatedFragment(AST::Attribute v):
m_type( InterpolatedFragment::META ),
- m_ptr( new AST::MetaItem(mv$(v)) )
+ m_ptr( new AST::Attribute(mv$(v)) )
{
}
InterpolatedFragment::InterpolatedFragment(::AST::Named<::AST::Item> v):
@@ -106,7 +106,7 @@ InterpolatedFragment::InterpolatedFragment(TypeRef v):
break;
case InterpolatedFragment::META:
- os << "meta[" << *reinterpret_cast<const AST::MetaItem*>(x.m_ptr) << "]";
+ os << "meta[" << *reinterpret_cast<const AST::Attribute*>(x.m_ptr) << "]";
break;
case InterpolatedFragment::ITEM: {
const auto& named_item = *reinterpret_cast<const AST::Named<AST::Item>*>(x.m_ptr);
diff --git a/src/parse/interpolated_fragment.hpp b/src/parse/interpolated_fragment.hpp
index 1b18845a..857e77aa 100644
--- a/src/parse/interpolated_fragment.hpp
+++ b/src/parse/interpolated_fragment.hpp
@@ -10,7 +10,7 @@ namespace AST {
class Pattern;
class Path;
class ExprNode;
- class MetaItem;
+ class Attribute;
template<typename T> struct Named;
class Item;
};
@@ -44,7 +44,7 @@ public:
InterpolatedFragment(::AST::Pattern);
InterpolatedFragment(::AST::Path);
InterpolatedFragment(::TypeRef);
- InterpolatedFragment(::AST::MetaItem );
+ InterpolatedFragment(::AST::Attribute );
InterpolatedFragment(::AST::Named<AST::Item> );
~InterpolatedFragment();
InterpolatedFragment(Type , ::AST::ExprNode*);
diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp
index 59b6b939..d103840e 100644
--- a/src/parse/paths.cpp
+++ b/src/parse/paths.cpp
@@ -203,7 +203,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
Token tok;
::std::vector<TypeRef> types;
- ::std::vector< ::std::string> lifetimes;
+ ::std::vector<AST::LifetimeRef> lifetimes;
::std::vector< ::std::pair< ::std::string, TypeRef > > assoc_bounds;
do {
@@ -214,7 +214,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
switch(GET_TOK(tok, lex))
{
case TOK_LIFETIME:
- lifetimes.push_back( tok.str() );
+ lifetimes.push_back(AST::LifetimeRef(/*lex.point_span(),*/ lex.get_ident(mv$(tok)) ));
break;
case TOK_IDENT:
if( LOOK_AHEAD(lex) == TOK_EQUAL )
diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp
index 974ff5fb..f6d61728 100644
--- a/src/parse/pattern.cpp
+++ b/src/parse/pattern.cpp
@@ -18,9 +18,9 @@ using AST::ExprNode;
::AST::Pattern::TuplePat Parse_PatternTuple(TokenStream& lex, bool is_refutable);
AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable);
-AST::Pattern Parse_PatternReal_Path(TokenStream& lex, AST::Path path, bool is_refutable);
+AST::Pattern Parse_PatternReal_Path(TokenStream& lex, ProtoSpan ps, AST::Path path, bool is_refutable);
AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable);
-AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refutable);
+AST::Pattern Parse_PatternStruct(TokenStream& lex, ProtoSpan ps, AST::Path path, bool is_refutable);
AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable);
AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable);
@@ -46,7 +46,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
if( tok.type() == TOK_IDENT && lex.lookahead(0) == TOK_EXCLAM )
{
lex.getToken();
- return AST::Pattern( AST::Pattern::TagMacro(), box$(Parse_MacroInvocation(ps, tok.str(), lex)));
+ return AST::Pattern( AST::Pattern::TagMacro(), lex.end_span(ps), box$(Parse_MacroInvocation(ps, tok.str(), lex)));
}
if( tok.type() == TOK_INTERPOLATED_PATTERN )
{
@@ -92,7 +92,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
if( GET_TOK(tok, lex) != TOK_AT )
{
PUTBACK(tok, lex);
- return AST::Pattern(AST::Pattern::TagBind(), mv$(bind_name), bind_type, is_mut);
+ return AST::Pattern(AST::Pattern::TagBind(), lex.end_span(ps), mv$(bind_name), bind_type, is_mut);
}
binding = AST::PatternBinding( mv$(bind_name), bind_type, is_mut );
@@ -126,11 +126,11 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
if( is_refutable ) {
assert(bind_type == ::AST::PatternBinding::Type::MOVE);
assert(is_mut == false);
- return AST::Pattern(AST::Pattern::TagMaybeBind(), mv$(name));
+ return AST::Pattern(AST::Pattern::TagMaybeBind(), lex.end_span(ps), mv$(name));
}
// Otherwise, it IS a binding
else {
- return AST::Pattern(AST::Pattern::TagBind(), mv$(name), bind_type, is_mut);
+ return AST::Pattern(AST::Pattern::TagBind(), lex.end_span(ps), mv$(name), bind_type, is_mut);
}
break;}
}
@@ -154,6 +154,7 @@ AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable)
GET_TOK(tok, lex);
return mv$(tok.frag_pattern());
}
+ auto ps = lex.start_span();
AST::Pattern ret = Parse_PatternReal1(lex, is_refutable);
if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT )
{
@@ -166,6 +167,7 @@ AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable)
throw ParseError::Generic(lex, "Using '...' with a non-value on right");
auto rightval = mv$( right_pat.data().as_Value().start );
ret_v.end = mv$(rightval);
+ // TODO: use `ps` here?
return ret;
}
@@ -178,6 +180,7 @@ AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable)
AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
{
TRACE_FUNCTION;
+ auto ps = lex.start_span();
Token tok;
AST::Path path;
@@ -185,11 +188,11 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
switch( GET_TOK(tok, lex) )
{
case TOK_UNDERSCORE:
- return AST::Pattern( );
+ return AST::Pattern( lex.end_span(ps), AST::Pattern::Data() );
//case TOK_DOUBLE_DOT:
// return AST::Pattern( AST::Pattern::TagWildcard() );
case TOK_RWORD_BOX:
- return AST::Pattern( AST::Pattern::TagBox(), Parse_Pattern(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagBox(), lex.end_span(ps), Parse_Pattern(lex, is_refutable) );
case TOK_DOUBLE_AMP:
lex.putback(TOK_AMP);
case TOK_AMP: {
@@ -200,7 +203,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
is_mut = true;
else
PUTBACK(tok, lex);
- return AST::Pattern( AST::Pattern::TagReference(), is_mut, Parse_Pattern(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagReference(), lex.end_span(ps), is_mut, Parse_Pattern(lex, is_refutable) );
}
case TOK_RWORD_SELF:
case TOK_RWORD_SUPER:
@@ -209,53 +212,53 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
case TOK_DOUBLE_LT:
case TOK_INTERPOLATED_PATH:
PUTBACK(tok, lex);
- return Parse_PatternReal_Path( lex, Parse_Path(lex, PATH_GENERIC_EXPR), is_refutable );
+ return Parse_PatternReal_Path( lex, ps, Parse_Path(lex, PATH_GENERIC_EXPR), is_refutable );
case TOK_DOUBLE_COLON:
// 2. Paths are enum/struct names
- return Parse_PatternReal_Path( lex, Parse_Path(lex, true, PATH_GENERIC_EXPR), is_refutable );
+ return Parse_PatternReal_Path( lex, ps, Parse_Path(lex, true, PATH_GENERIC_EXPR), is_refutable );
case TOK_DASH:
if(GET_TOK(tok, lex) == TOK_INTEGER)
{
auto dt = tok.datatype();
// TODO: Ensure that the type is ANY or a signed integer
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Integer({dt, -tok.intval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({dt, -tok.intval()}) );
}
else if( tok.type() == TOK_FLOAT )
{
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Float({tok.datatype(), -tok.floatval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Float({tok.datatype(), -tok.floatval()}) );
}
else
{
throw ParseError::Unexpected(lex, tok, {TOK_INTEGER, TOK_FLOAT});
}
case TOK_FLOAT:
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Float({tok.datatype(), tok.floatval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Float({tok.datatype(), tok.floatval()}) );
case TOK_INTEGER:
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Integer({tok.datatype(), tok.intval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({tok.datatype(), tok.intval()}) );
case TOK_RWORD_TRUE:
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 1}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 1}) );
case TOK_RWORD_FALSE:
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 0}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 0}) );
case TOK_STRING:
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_String( mv$(tok.str()) ) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_String( mv$(tok.str()) ) );
case TOK_BYTESTRING:
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_ByteString({ mv$(tok.str()) }) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_ByteString({ mv$(tok.str()) }) );
case TOK_INTERPOLATED_EXPR: {
auto e = tok.take_frag_node();
if( auto* n = dynamic_cast<AST::ExprNode_String*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_String( mv$(n->m_value) ) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_String( mv$(n->m_value) ) );
}
//else if( auto* n = dynamic_cast<AST::ExprNode_ByteString*>(e.get()) ) {
- // return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_ByteString( mv$(n->m_value) ) );
+ // return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_ByteString( mv$(n->m_value) ) );
//}
else if( auto* n = dynamic_cast<AST::ExprNode_Bool*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, n->m_value}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, n->m_value}) );
}
else if( auto* n = dynamic_cast<AST::ExprNode_Integer*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Integer({n->m_datatype, n->m_value}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({n->m_datatype, n->m_value}) );
}
else if( auto* n = dynamic_cast<AST::ExprNode_Float*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Float({n->m_datatype, n->m_value}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Float({n->m_datatype, n->m_value}) );
}
else {
TODO(lex.point_span(), "Convert :expr into a pattern value - " << *e);
@@ -263,32 +266,32 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
} break;
case TOK_PAREN_OPEN:
- return AST::Pattern( AST::Pattern::TagTuple(), Parse_PatternTuple(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagTuple(), lex.end_span(ps), Parse_PatternTuple(lex, is_refutable) );
case TOK_SQUARE_OPEN:
return Parse_PatternReal_Slice(lex, is_refutable);
default:
throw ParseError::Unexpected(lex, tok);
}
}
-AST::Pattern Parse_PatternReal_Path(TokenStream& lex, AST::Path path, bool is_refutable)
+AST::Pattern Parse_PatternReal_Path(TokenStream& lex, ProtoSpan ps, AST::Path path, bool is_refutable)
{
Token tok;
switch( GET_TOK(tok, lex) )
{
case TOK_PAREN_OPEN:
- return AST::Pattern( AST::Pattern::TagNamedTuple(), mv$(path), Parse_PatternTuple(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagNamedTuple(), lex.end_span(ps), mv$(path), Parse_PatternTuple(lex, is_refutable) );
case TOK_BRACE_OPEN:
- return Parse_PatternStruct(lex, mv$(path), is_refutable);
+ return Parse_PatternStruct(lex, ps, mv$(path), is_refutable);
default:
PUTBACK(tok, lex);
- return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(mv$(path)) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Named(mv$(path)) );
}
}
AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
{
- auto sp = lex.start_span();
+ auto ps = lex.start_span();
Token tok;
::std::vector< ::AST::Pattern> leading;
@@ -320,7 +323,7 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
if( has_binding ) {
if(is_split)
- ERROR(lex.end_span(sp), E0000, "Multiple instances of .. in a slice pattern");
+ ERROR(lex.end_span(ps), E0000, "Multiple instances of .. in a slice pattern");
inner_binding = mv$(binding);
is_split = true;
@@ -343,13 +346,13 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
if( is_split )
{
- return ::AST::Pattern( ::AST::Pattern::Data::make_SplitSlice({ mv$(leading), mv$(inner_binding), mv$(trailing) }) );
+ return ::AST::Pattern( lex.end_span(ps), ::AST::Pattern::Data::make_SplitSlice({ mv$(leading), mv$(inner_binding), mv$(trailing) }) );
}
else
{
assert( !inner_binding.is_valid() );
assert( trailing.empty() );
- return ::AST::Pattern( ::AST::Pattern::Data::make_Slice({ mv$(leading) }) );
+ return ::AST::Pattern( lex.end_span(ps), ::AST::Pattern::Data::make_Slice({ mv$(leading) }) );
}
}
@@ -398,7 +401,7 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
return ::AST::Pattern::TuplePat { mv$(leading), true, mv$(trailing) };
}
-AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refutable)
+AST::Pattern Parse_PatternStruct(TokenStream& lex, ProtoSpan ps, AST::Path path, bool is_refutable)
{
TRACE_FUNCTION;
Token tok;
@@ -449,7 +452,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
i ++;
}
- return AST::Pattern(AST::Pattern::TagNamedTuple(), mv$(path), AST::Pattern::TuplePat { mv$(leading), has_split, mv$(trailing) });
+ return AST::Pattern(AST::Pattern::TagNamedTuple(), lex.end_span(ps), mv$(path), AST::Pattern::TuplePat { mv$(leading), has_split, mv$(trailing) });
}
bool is_exhaustive = true;
@@ -465,6 +468,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
break;
}
+ auto inner_ps = lex.start_span();
bool is_short_bind = false;
bool is_box = false;
auto bind_type = AST::PatternBinding::Type::MOVE;
@@ -499,12 +503,12 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
AST::Pattern pat;
if( is_short_bind || tok.type() != TOK_COLON ) {
PUTBACK(tok, lex);
- pat = AST::Pattern();
+ pat = AST::Pattern(lex.end_span(inner_ps), {});
field_name = field_ident.name;
pat.set_bind(mv$(field_ident), bind_type, is_mut);
if( is_box )
{
- pat = AST::Pattern(AST::Pattern::TagBox(), mv$(pat));
+ pat = AST::Pattern(AST::Pattern::TagBox(), lex.end_span(inner_ps), mv$(pat));
}
}
else {
@@ -517,6 +521,6 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
} while( GET_TOK(tok, lex) == TOK_COMMA );
CHECK_TOK(tok, TOK_BRACE_CLOSE);
- return AST::Pattern(AST::Pattern::TagStruct(), ::std::move(path), ::std::move(subpats), is_exhaustive);
+ return AST::Pattern(AST::Pattern::TagStruct(), lex.end_span(ps), ::std::move(path), ::std::move(subpats), is_exhaustive);
}
diff --git a/src/parse/root.cpp b/src/parse/root.cpp
index 8fa72fb3..68ad570b 100644
--- a/src/parse/root.cpp
+++ b/src/parse/root.cpp
@@ -41,10 +41,10 @@ Spanned<T> get_spanned(TokenStream& lex, ::std::function<T()> f) {
return input;
}
-AST::MetaItems Parse_ItemAttrs(TokenStream& lex);
-void Parse_ParentAttrs(TokenStream& lex, AST::MetaItems& out);
-AST::MetaItem Parse_MetaItem(TokenStream& lex);
-void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::MetaItems& mod_attrs);
+AST::AttributeList Parse_ItemAttrs(TokenStream& lex);
+void Parse_ParentAttrs(TokenStream& lex, AST::AttributeList& out);
+AST::Attribute Parse_MetaItem(TokenStream& lex);
+void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::AttributeList& mod_attrs);
bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv);
//::AST::Path Parse_Publicity(TokenStream& lex)
@@ -119,31 +119,55 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true)
}
}
-::std::vector< ::std::string> Parse_HRB(TokenStream& lex)
+::AST::HigherRankedBounds Parse_HRB(TokenStream& lex)
{
TRACE_FUNCTION;
Token tok;
- ::std::vector< ::std::string> lifetimes;
+ ::AST::HigherRankedBounds rv;
GET_CHECK_TOK(tok, lex, TOK_LT);
do {
- ::AST::MetaItems attrs = Parse_ItemAttrs(lex);
- (void)attrs; // TODO: Attributes on generic params
+ // Support empty lists and comma-terminated lists
+ if( lex.lookahead(0) == TOK_GT ) {
+ GET_TOK(tok, lex);
+ break;
+ }
+ auto attrs = Parse_ItemAttrs(lex);
switch(GET_TOK(tok, lex))
{
case TOK_LIFETIME:
- lifetimes.push_back(tok.str());
+ rv.m_lifetimes.push_back(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), Ident(lex.getHygiene(), tok.str())));
break;
default:
throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME));
}
} while( GET_TOK(tok, lex) == TOK_COMMA );
CHECK_TOK(tok, TOK_GT);
- return lifetimes;
+ return rv;
+}
+::AST::HigherRankedBounds Parse_HRB_Opt(TokenStream& lex)
+{
+ if( lex.lookahead(0) == TOK_RWORD_FOR )
+ {
+ lex.getToken(); // Consume
+ return Parse_HRB(lex);
+ }
+ else
+ {
+ return ::AST::HigherRankedBounds();
+ }
+}
+
+namespace {
+ AST::LifetimeRef get_LifetimeRef(TokenStream& lex, Token tok)
+ {
+ CHECK_TOK(tok, TOK_LIFETIME);
+ return AST::LifetimeRef(/*lex.point_span(), */Ident(lex.getHygiene(), mv$(tok.str())));
+ }
}
/// Parse type parameters in a definition
-void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_type, ::std::vector< ::std::string> lifetimes = {})
+void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_type, AST::HigherRankedBounds outer_hrbs = {})
{
TRACE_FUNCTION;
Token tok;
@@ -156,29 +180,32 @@ void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_
// return;
//}
- ::std::vector< ::std::string> hrls;
if(GET_TOK(tok, lex) == TOK_LIFETIME) {
ret.add_bound(AST::GenericBound::make_TypeLifetime( {
- checked_type.clone(), tok.str()
+ checked_type.clone(), get_LifetimeRef(lex, mv$(tok))
} ));
}
else if( tok.type() == TOK_QMARK ) {
+ auto hrbs = Parse_HRB_Opt(lex);
+ (void)hrbs; // The only valid ?Trait is Sized, which doesn't have any generics
ret.add_bound(AST::GenericBound::make_MaybeTrait( {
checked_type.clone(), Parse_Path(lex, PATH_GENERIC_TYPE)
} ));
}
else {
+ ::AST::HigherRankedBounds inner_hrls;
if( tok.type() == TOK_RWORD_FOR )
{
- hrls = Parse_HRB(lex);
+ inner_hrls = Parse_HRB(lex);
}
else {
PUTBACK(tok, lex);
}
- (void)hrls; // TODO: HRLs
+ auto trait_path = Parse_Path(lex, PATH_GENERIC_TYPE);
+ auto this_outer_hrbs = (lex.lookahead(0) == TOK_PLUS ? AST::HigherRankedBounds(outer_hrbs) : mv$(outer_hrbs));
ret.add_bound( AST::GenericBound::make_IsTrait({
- checked_type.clone(), mv$(lifetimes), Parse_Path(lex, PATH_GENERIC_TYPE)
+ mv$(this_outer_hrbs), checked_type.clone(), mv$(inner_hrls), mv$(trait_path)
}) );
}
} while( GET_TOK(tok, lex) == TOK_PLUS );
@@ -198,15 +225,13 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex)
}
PUTBACK(tok, lex);
- ::AST::MetaItems attrs = Parse_ItemAttrs(lex);
- (void)attrs; // TODO: Attributes on generic params
+ auto attrs = Parse_ItemAttrs(lex);
GET_TOK(tok, lex);
if( tok.type() == TOK_IDENT )
{
- // TODO: Hygine
::std::string param_name = mv$(tok.str());
- ret.add_ty_param( AST::TypeParam( param_name ) );
+ ret.add_ty_param( AST::TypeParam( lex.point_span(), ::std::move(attrs), param_name ) );
auto param_ty = TypeRef(lex.point_span(), param_name);
if( GET_TOK(tok, lex) == TOK_COLON )
@@ -223,14 +248,14 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex)
}
else if( tok.type() == TOK_LIFETIME )
{
- // TODO: Should lifetimes have hygine?
- ::std::string param_name = tok.str();
- ret.add_lft_param( param_name );
+ auto param_name = tok.str();
+ auto ref = get_LifetimeRef(lex, mv$(tok));
+ ret.add_lft_param(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), Ident(lex.getHygiene(), param_name) ));
if( GET_TOK(tok, lex) == TOK_COLON )
{
do {
GET_CHECK_TOK(tok, lex, TOK_LIFETIME);
- ret.add_bound(AST::GenericBound::make_Lifetime( {param_name, tok.str()} ));
+ ret.add_bound(AST::GenericBound::make_Lifetime({ AST::LifetimeRef(ref), get_LifetimeRef(lex, mv$(tok)) }));
} while( GET_TOK(tok, lex) == TOK_PLUS );
}
}
@@ -258,11 +283,11 @@ void Parse_WhereClause(TokenStream& lex, AST::GenericParams& params)
if( tok.type() == TOK_LIFETIME )
{
- auto lhs = mv$(tok.str());
+ auto lhs = get_LifetimeRef(lex, mv$(tok));
GET_CHECK_TOK(tok, lex, TOK_COLON);
do {
GET_CHECK_TOK(tok, lex, TOK_LIFETIME);
- auto rhs = mv$(tok.str());
+ auto rhs = get_LifetimeRef(lex, mv$(tok));
params.add_bound( AST::GenericBound::make_Lifetime({lhs, rhs}) );
} while( GET_TOK(tok, lex) == TOK_PLUS );
PUTBACK(tok, lex);
@@ -270,11 +295,11 @@ void Parse_WhereClause(TokenStream& lex, AST::GenericParams& params)
// Higher-ranked types/lifetimes
else if( tok.type() == TOK_RWORD_FOR )
{
- ::std::vector< ::std::string> lifetimes = Parse_HRB(lex);
+ auto hrbs = Parse_HRB(lex);
TypeRef type = Parse_Type(lex);
GET_CHECK_TOK(tok, lex, TOK_COLON);
- Parse_TypeBound(lex,params, mv$(type), mv$(lifetimes));
+ Parse_TypeBound(lex,params, mv$(type), mv$(hrbs));
}
else
{
@@ -346,38 +371,32 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_
if( tok.type() == TOK_AMP )
{
// By-reference method?
- // TODO: If a lifetime is seen (and not a prototype), it is definitely a self binding
unsigned int ofs = 0;
+ // Handle a lifetime parameter name
if( lex.lookahead(0) == TOK_LIFETIME )
ofs ++;
if( lex.lookahead(ofs) == TOK_RWORD_SELF || (lex.lookahead(ofs) == TOK_RWORD_MUT && lex.lookahead(ofs+1) == TOK_RWORD_SELF) )
{
auto ps = lex.start_span();
- ::std::string lifetime;
+ AST::LifetimeRef lifetime;
if( GET_TOK(tok, lex) == TOK_LIFETIME ) {
- lifetime = tok.str();
+ lifetime = get_LifetimeRef(lex, mv$(tok));
GET_TOK(tok, lex);
}
- auto ty_sp = lex.end_span(ps);
+ bool is_mut = false;
if( tok.type() == TOK_RWORD_MUT )
{
- GET_CHECK_TOK(tok, lex, TOK_RWORD_SELF);
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, true, TypeRef(ty_sp, "Self", 0xFFFF))) );
- }
- else
- {
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, false, TypeRef(ty_sp, "Self", 0xFFFF))) );
+ is_mut = true;
+ GET_TOK(tok, lex);
}
- DEBUG("TODO: UFCS / self lifetimes");
+ CHECK_TOK(tok, TOK_RWORD_SELF);
+ auto sp = lex.end_span(ps);
+ args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, ::std::move(lifetime), is_mut, TypeRef(sp, "Self", 0xFFFF))) );
if( allow_self == false )
throw ParseError::Generic(lex, "Self binding not expected");
- //args.push_back( ::std::make_pair(
- // AST::Pattern(),
- // TypeRef(TypeRef::TagReference(), lifetime, (fcn_class == AST::Function::CLASS_MUTMETHOD), )
- //) );
// Prime tok for next step
GET_TOK(tok, lex);
@@ -394,6 +413,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_
GET_TOK(tok, lex);
if( allow_self == false )
throw ParseError::Generic(lex, "Self binding not expected");
+ auto binding_sp = lex.end_span(ps);
TypeRef ty = TypeRef( lex.point_span(), "Self", 0xFFFF );
if( GET_TOK(tok, lex) == TOK_COLON ) {
// Typed mut self
@@ -402,7 +422,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_
else {
PUTBACK(tok, lex);
}
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), mv$(ty)) );
+ args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), binding_sp, "self"), mv$(ty)) );
GET_TOK(tok, lex);
}
}
@@ -411,6 +431,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_
// By-value method
if( allow_self == false )
throw ParseError::Generic(lex, "Self binding not expected");
+ auto binding_sp = lex.end_span(ps);
TypeRef ty = TypeRef( lex.point_span(), "Self", 0xFFFF );
if( GET_TOK(tok, lex) == TOK_COLON ) {
// Typed mut self
@@ -419,7 +440,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_
else {
PUTBACK(tok, lex);
}
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), mv$(ty)) );
+ args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), binding_sp, "self"), mv$(ty)) );
GET_TOK(tok, lex);
}
else
@@ -486,7 +507,7 @@ AST::Function Parse_FunctionDefWithCode(TokenStream& lex, ::std::string abi, boo
Token tok;
auto ret = Parse_FunctionDef(lex, abi, allow_self, false, is_unsafe, is_const);
GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
- // Enter a new hygine scope (TODO: Should this be in Parse_ExprBlock?)
+ // Enter a new hygine scope for the function (TODO: Should this be in Parse_ExprBlock?)
lex.push_hygine();
PUTBACK(tok, lex);
ret.set_code( Parse_ExprBlock(lex) );
@@ -523,7 +544,7 @@ AST::TypeAlias Parse_TypeAlias(TokenStream& lex)
return AST::TypeAlias( ::std::move(params), ::std::move(type) );
}
-AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items)
+AST::Struct Parse_Struct(TokenStream& lex, const AST::AttributeList& meta_items)
{
TRACE_FUNCTION;
@@ -547,7 +568,7 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items)
::std::vector<AST::TupleItem> refs;
while(lex.lookahead(0) != TOK_PAREN_CLOSE)
{
- AST::MetaItems item_attrs = Parse_ItemAttrs(lex);
+ auto item_attrs = Parse_ItemAttrs(lex);
SET_ATTRS(lex, item_attrs);
bool is_pub = Parse_Publicity(lex, /*allow_restricted=*/false); // HACK: Disable `pub(restricted)` syntax in tuple structs, due to ambiguity
@@ -582,7 +603,7 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items)
{
PUTBACK(tok, lex);
- AST::MetaItems item_attrs = Parse_ItemAttrs(lex);
+ auto item_attrs = Parse_ItemAttrs(lex);
SET_ATTRS(lex, item_attrs);
bool is_pub = Parse_Publicity(lex);
@@ -607,7 +628,7 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items)
}
}
-AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
+AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items)
{
TRACE_FUNCTION;
@@ -622,30 +643,27 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
}
// Trait bounds "trait Trait : 'lifetime + OtherTrait + OtherTrait2"
- ::std::vector<Spanned<AST::Path> > supertraits;
+ ::std::vector<Spanned<Type_TraitPath> > supertraits;
if(tok.type() == TOK_COLON)
{
+ // TODO: Just add these as `where Self: <foo>` (would that break typecheck?)
do {
if( GET_TOK(tok, lex) == TOK_LIFETIME ) {
// TODO: Need a better way of indiciating 'static than just an invalid path
- supertraits.push_back( make_spanned( Span(tok.get_pos()), AST::Path() ) );
+ ASSERT_BUG(lex.point_span(), tok.str() == "static", "TODO: Support lifetimes other than 'static in trait bounds");
+ supertraits.push_back( make_spanned( Span(tok.get_pos()), Type_TraitPath{ {}, AST::Path() } ) );
}
else if( tok.type() == TOK_BRACE_OPEN ) {
break;
}
else {
PUTBACK(tok, lex);
- if( LOOK_AHEAD(lex) == TOK_RWORD_FOR )
- {
- GET_TOK(tok, lex);
- /*::std::vector< ::std::string> lifetimes =*/ Parse_HRB(lex);
- }
- supertraits.push_back( GET_SPANNED(::AST::Path, lex, Parse_Path(lex, PATH_GENERIC_TYPE)) );
+ auto hrbs = Parse_HRB_Opt(lex);
+ supertraits.push_back( GET_SPANNED(Type_TraitPath, lex, (Type_TraitPath{ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) })) );
}
} while( GET_TOK(tok, lex) == TOK_PLUS );
}
- // TODO: Support "for Sized?"
if(tok.type() == TOK_RWORD_WHERE)
{
//if( params.ty_params().size() == 0 )
@@ -662,7 +680,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
{
PUTBACK(tok, lex);
- AST::MetaItems item_attrs = Parse_ItemAttrs(lex);
+ auto item_attrs = Parse_ItemAttrs(lex);
SET_ATTRS(lex, item_attrs);
auto ps = lex.start_span();
@@ -747,7 +765,6 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
break; }
// Functions (possibly unsafe)
- // TODO: Const?
case TOK_RWORD_UNSAFE:
fn_is_unsafe = true;
if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN )
@@ -770,8 +787,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
if( GET_TOK(tok, lex) == TOK_BRACE_OPEN )
{
PUTBACK(tok, lex);
- // Enter a new hygine scope for the function body.
- // - TODO: Should this just happen in Parse_ExprBlock?
+ // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?)
lex.push_hygine();
fcn.set_code( Parse_ExprBlock(lex) );
lex.pop_hygine();
@@ -784,7 +800,6 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
{
throw ParseError::Unexpected(lex, tok);
}
- // TODO: Store `item_attrs`
trait.add_function( ::std::move(name), mv$(item_attrs), ::std::move(fcn) );
break; }
default:
@@ -795,7 +810,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
return trait;
}
-AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items)
+AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items)
{
TRACE_FUNCTION;
@@ -823,7 +838,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items)
auto sp = lex.start_span();
PUTBACK(tok, lex);
- AST::MetaItems item_attrs = Parse_ItemAttrs(lex);
+ auto item_attrs = Parse_ItemAttrs(lex);
SET_ATTRS(lex, item_attrs);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
@@ -841,8 +856,8 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items)
break;
}
- AST::MetaItems field_attrs = Parse_ItemAttrs(lex);
- (void)field_attrs; // TODO^
+ auto field_attrs = Parse_ItemAttrs(lex);
+ (void)field_attrs; // TODO: Store field_attrs
types.push_back( Parse_Type(lex) );
} while( GET_TOK(tok, lex) == TOK_COMMA );
@@ -862,7 +877,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items)
break;
}
- AST::MetaItems field_attrs = Parse_ItemAttrs(lex);
+ auto field_attrs = Parse_ItemAttrs(lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
auto name = mv$(tok.str());
@@ -897,7 +912,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items)
return AST::Enum( mv$(params), mv$(variants) );
}
-::AST::Union Parse_Union(TokenStream& lex, AST::MetaItems& meta_items)
+::AST::Union Parse_Union(TokenStream& lex, AST::AttributeList& meta_items)
{
Token tok;
@@ -924,7 +939,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items)
break ;
}
- AST::MetaItems item_attrs = Parse_ItemAttrs(lex);
+ auto item_attrs = Parse_ItemAttrs(lex);
SET_ATTRS(lex, item_attrs);
bool is_pub = Parse_Publicity(lex);
@@ -943,9 +958,9 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items)
return ::AST::Union( mv$(params), mv$(variants) );
}
-AST::MetaItems Parse_ItemAttrs(TokenStream& lex)
+AST::AttributeList Parse_ItemAttrs(TokenStream& lex)
{
- AST::MetaItems rv;
+ AST::AttributeList rv;
Token tok;
while( lex.lookahead(0) == TOK_HASH )
{
@@ -956,7 +971,7 @@ AST::MetaItems Parse_ItemAttrs(TokenStream& lex)
}
return rv;
}
-void Parse_ParentAttrs(TokenStream& lex, AST::MetaItems& out)
+void Parse_ParentAttrs(TokenStream& lex, AST::AttributeList& out)
{
Token tok;
while( lex.lookahead(0) == TOK_HASH && lex.lookahead(1) == TOK_EXCLAM )
@@ -969,7 +984,7 @@ void Parse_ParentAttrs(TokenStream& lex, AST::MetaItems& out)
}
}
/// Parse a meta-item declaration (either #![ or #[)
-AST::MetaItem Parse_MetaItem(TokenStream& lex)
+AST::Attribute Parse_MetaItem(TokenStream& lex)
{
TRACE_FUNCTION;
Token tok;
@@ -979,6 +994,7 @@ AST::MetaItem Parse_MetaItem(TokenStream& lex)
return mv$(tok.frag_meta());
}
+ auto ps = lex.start_span();
CHECK_TOK(tok, TOK_IDENT);
::std::string name = mv$(tok.str());
switch(GET_TOK(tok, lex))
@@ -987,24 +1003,26 @@ AST::MetaItem Parse_MetaItem(TokenStream& lex)
switch(GET_TOK(tok, lex))
{
case TOK_STRING:
- return AST::MetaItem(name, tok.str());
+ return AST::Attribute(lex.end_span(ps), name, tok.str());
case TOK_INTERPOLATED_EXPR: {
auto n = tok.take_frag_node();
if( auto* v = dynamic_cast<::AST::ExprNode_String*>(&*n) )
{
- return AST::MetaItem(name, mv$(v->m_value));
+ return AST::Attribute(lex.end_span(ps), name, mv$(v->m_value));
}
else
{
+ // - Force an error.
CHECK_TOK(tok, TOK_STRING);
}
break; }
default:
+ // - Force an error.
CHECK_TOK(tok, TOK_STRING);
}
throw "";
case TOK_PAREN_OPEN: {
- ::std::vector<AST::MetaItem> items;
+ ::std::vector<AST::Attribute> items;
do {
if(LOOK_AHEAD(lex) == TOK_PAREN_CLOSE) {
GET_TOK(tok, lex);
@@ -1013,14 +1031,14 @@ AST::MetaItem Parse_MetaItem(TokenStream& lex)
items.push_back(Parse_MetaItem(lex));
} while(GET_TOK(tok, lex) == TOK_COMMA);
CHECK_TOK(tok, TOK_PAREN_CLOSE);
- return AST::MetaItem(name, mv$(items)); }
+ return AST::Attribute(lex.end_span(ps), name, mv$(items)); }
default:
PUTBACK(tok, lex);
- return AST::MetaItem(name);
+ return AST::Attribute(lex.end_span(ps), name);
}
}
-::AST::Item Parse_Impl(TokenStream& lex, AST::MetaItems attrs, bool is_unsafe=false)
+::AST::Item Parse_Impl(TokenStream& lex, AST::AttributeList attrs, bool is_unsafe=false)
{
TRACE_FUNCTION;
Token tok;
@@ -1057,7 +1075,7 @@ AST::MetaItem Parse_MetaItem(TokenStream& lex)
// negative impls can't have any content
GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- return ::AST::Item::make_NegImpl( AST::ImplDef(lex.end_span(ps), mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ) );
+ return ::AST::Item::make_NegImpl(AST::ImplDef( mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ));
}
// - Don't care which at this stage
@@ -1102,7 +1120,7 @@ AST::MetaItem Parse_MetaItem(TokenStream& lex)
Parse_ParentAttrs(lex, attrs);
- AST::Impl impl( AST::ImplDef( lex.end_span(ps), mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ) );
+ auto impl = AST::Impl(AST::ImplDef( mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ));
// A sequence of method implementations
while( lex.lookahead(0) != TOK_BRACE_CLOSE )
@@ -1119,7 +1137,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
TRACE_FUNCTION;
Token tok;
- AST::MetaItems item_attrs = Parse_ItemAttrs(lex);
+ auto item_attrs = Parse_ItemAttrs(lex);
SET_ATTRS(lex, item_attrs);
{
@@ -1173,8 +1191,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
auto i = ::AST::Static(AST::Static::CONST, mv$(ty), mv$(val));
- // TODO: Attributes on associated constants
- impl.add_static( is_public, is_specialisable, mv$(name), mv$(i) /*, mv$(item_attrs)*/ );
+ impl.add_static( is_public, is_specialisable, mv$(name), mv$(i) );
break ;
}
else if( tok.type() == TOK_RWORD_UNSAFE )
@@ -1216,7 +1233,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
impl.items().back().data->attrs = mv$(item_attrs); // Empty for functions
}
-AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::MetaItems& block_attrs)
+AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::AttributeList& block_attrs)
{
TRACE_FUNCTION;
Token tok;
@@ -1228,7 +1245,7 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::M
while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
{
PUTBACK(tok, lex);
- AST::MetaItems meta_items = Parse_ItemAttrs(lex);
+ auto meta_items = Parse_ItemAttrs(lex);
SET_ATTRS(lex, meta_items);
auto ps = lex.start_span();
@@ -1452,7 +1469,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
return true;
}
-::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::MetaItems meta_items)
+::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::AttributeList meta_items)
{
TRACE_FUNCTION_F("mod_path="<<mod_path<<", meta_items="<<meta_items);
Token tok;
@@ -1644,7 +1661,6 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `unsafe trait`
// `unsafe impl`
case TOK_RWORD_UNSAFE:
- meta_items.push_back( AST::MetaItem("#UNSAFE") );
switch(GET_TOK(tok, lex))
{
// `unsafe extern fn`
@@ -1669,16 +1685,27 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,false/*unsafe,const*/) );
break;
// `unsafe trait`
- case TOK_RWORD_TRAIT:
+ case TOK_RWORD_TRAIT: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
item_name = mv$(tok.str());
- // TODO: Mark as unsafe
- meta_items.push_back( AST::MetaItem("#UNSAFE") );
- item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) );
- break;
+ auto tr = Parse_TraitDef(lex, meta_items);
+ tr.set_is_unsafe();
+ item_data = ::AST::Item( ::std::move(tr) );
+ break; }
// `unsafe impl`
- case TOK_RWORD_IMPL:
- return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items), true), false };
+ case TOK_RWORD_IMPL: {
+ auto impl = Parse_Impl(lex, mv$(meta_items), true);
+ if( impl.is_Impl() ) {
+ impl.as_Impl().def().set_is_unsafe();
+ }
+ else if( impl.is_NegImpl() ) {
+ impl.as_NegImpl().set_is_unsafe();
+ }
+ else {
+ BUG(lex.point_span(), "Parse_Impl returned a variant other than Impl or NegImpl");
+ }
+ return ::AST::Named< ::AST::Item> { "", mv$(impl), false };
+ }
default:
throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_TRAIT, TOK_RWORD_IMPL});
}
@@ -1772,10 +1799,10 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// Check #[cfg] and don't load if it fails
struct H {
- static bool check_item_cfg(const ::AST::MetaItems& attrs)
+ static bool check_item_cfg(const ::AST::AttributeList& attrs)
{
for(const auto& at : attrs.m_items) {
- if( at.name() == "cfg" && !check_cfg(attrs.m_span, at) ) {
+ if( at.name() == "cfg" && !check_cfg(at.span(), at) ) {
return false;
}
}
@@ -1853,7 +1880,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
return ::AST::Named< ::AST::Item> { mv$(item_name), mv$(item_data), is_public };
}
-void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items)
+void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_items)
{
SET_MODULE(lex, mod);
lex.parse_state().parent_attrs = &meta_items;
@@ -1899,14 +1926,14 @@ void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod)
}
// Attributes on the following item
- AST::MetaItems meta_items = Parse_ItemAttrs(lex);
+ auto meta_items = Parse_ItemAttrs(lex);
DEBUG("meta_items = " << meta_items);
Parse_Mod_Item(lex, mod, mv$(meta_items));
}
}
-void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::MetaItems& mod_attrs)
+void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::AttributeList& mod_attrs)
{
TRACE_FUNCTION;
diff --git a/src/parse/token.cpp b/src/parse/token.cpp
index 768a96bc..115df135 100644
--- a/src/parse/token.cpp
+++ b/src/parse/token.cpp
@@ -33,7 +33,7 @@ Token::~Token()
delete reinterpret_cast<AST::ExprNode*>(m_data.as_Fragment());
break;
case TOK_INTERPOLATED_META:
- delete reinterpret_cast<AST::MetaItem*>(m_data.as_Fragment());
+ delete reinterpret_cast<AST::Attribute*>(m_data.as_Fragment());
break;
default:
break;
@@ -92,7 +92,7 @@ Token::Token(const InterpolatedFragment& frag)
break;
case InterpolatedFragment::META:
m_type = TOK_INTERPOLATED_META;
- m_data = new AST::MetaItem( reinterpret_cast<const AST::MetaItem*>(frag.m_ptr)->clone() );
+ m_data = new AST::Attribute( reinterpret_cast<const AST::Attribute*>(frag.m_ptr)->clone() );
break;
case InterpolatedFragment::ITEM: {
m_type = TOK_INTERPOLATED_ITEM;
@@ -197,11 +197,11 @@ Token Token::clone() const
rv.m_data = reinterpret_cast<AST::ExprNode*>(e)->clone().release();
break;
case TOK_INTERPOLATED_META:
- rv.m_data = new AST::MetaItem( reinterpret_cast<AST::MetaItem*>(e)->clone() );
+ rv.m_data = new AST::Attribute( reinterpret_cast<AST::Attribute*>(e)->clone() );
break;
case TOK_INTERPOLATED_ITEM:
TODO(m_pos, "clone interpolated item");
- //rv.m_data = new AST::Named( AST::Item( reinterpret_cast<AST::MetaItem*>(e)->clone() ) );
+ //rv.m_data = new AST::Named( AST::Item( reinterpret_cast<AST::Attribute*>(e)->clone() ) );
break;
default:
BUG(m_pos, "Fragment with invalid token type (" << *this << ")");
@@ -297,7 +297,7 @@ struct EscapedString {
reinterpret_cast<const ::AST::Path*>(m_data.as_Fragment())->print_pretty(ss, true);
return ss.str();
case TOK_INTERPOLATED_PATTERN:
- // TODO: Use a configurable print
+ // TODO: Use a pretty printer too?
return FMT( *reinterpret_cast<const ::AST::Pattern*>(m_data.as_Fragment()) );
case TOK_INTERPOLATED_STMT:
case TOK_INTERPOLATED_BLOCK:
@@ -312,9 +312,21 @@ struct EscapedString {
// Value tokens
case TOK_IDENT: return m_data.as_String();
case TOK_LIFETIME: return "'" + m_data.as_String();
- case TOK_INTEGER: return FMT(m_data.as_Integer().m_intval); // TODO: suffix for type
+ case TOK_INTEGER:
+ if( m_data.as_Integer().m_datatype == CORETYPE_ANY ) {
+ return FMT(m_data.as_Integer().m_intval);
+ }
+ else {
+ return FMT(m_data.as_Integer().m_intval << "_" << m_data.as_Integer().m_datatype);
+ }
case TOK_CHAR: return FMT("'\\u{"<< ::std::hex << m_data.as_Integer().m_intval << "}");
- case TOK_FLOAT: return FMT(m_data.as_Float().m_floatval);
+ case TOK_FLOAT:
+ if( m_data.as_Float().m_datatype == CORETYPE_ANY ) {
+ return FMT(m_data.as_Float().m_floatval);
+ }
+ else {
+ return FMT(m_data.as_Float().m_floatval << "_" << m_data.as_Float().m_datatype);
+ }
case TOK_STRING: return FMT("\"" << EscapedString(m_data.as_String()) << "\"");
case TOK_BYTESTRING:return FMT("b\"" << m_data.as_String() << "\"");
case TOK_HASH: return "#";
@@ -445,78 +457,6 @@ struct EscapedString {
throw ParseError::BugCheck("Reached end of Token::to_str");
}
-void operator%(::Serialiser& s, enum eTokenType c) {
- s << Token::typestr(c);
-}
-void operator%(::Deserialiser& s, enum eTokenType& c) {
- ::std::string n;
- s.item(n);
- c = Token::typefromstr(n);
-}
-void operator%(::Serialiser& s, enum eCoreType t) {
- s << coretype_name(t);
-}
-void operator%(::Deserialiser& s, enum eCoreType& t) {
- ::std::string n;
- s.item(n);
- t = coretype_fromstring(n);
- ASSERT_BUG(Span(), t != CORETYPE_INVAL, "Invalid coretype '" << n << "'");
-}
-SERIALISE_TYPE(Token::, "Token", {
- s % m_type;
- s << Token::Data::tag_to_str(m_data.tag());
- TU_MATCH(Token::Data, (m_data), (e),
- (None, ),
- (String,
- s << e;
- ),
- (Integer,
- s % e.m_datatype;
- s.item( e.m_intval );
- ),
- (Float,
- s % e.m_datatype;
- s.item( e.m_floatval );
- ),
- (Fragment,
- assert(!"Serialising interpolated macro fragment");
- )
- )
-},{
- s % m_type;
- Token::Data::Tag tag;
- {
- ::std::string tag_str;
- s.item( tag_str );
- tag = Token::Data::tag_from_str(tag_str);
- }
- switch(tag)
- {
- case Token::Data::TAGDEAD: break;
- case Token::Data::TAG_None: break;
- case Token::Data::TAG_String: {
- ::std::string str;
- s.item( str );
- m_data = Token::Data::make_String(str);
- break; }
- case Token::Data::TAG_Integer: {
- enum eCoreType dt;
- uint64_t v;
- s % dt;
- s.item( v );
- m_data = Token::Data::make_Integer({dt, v});
- break; }
- case Token::Data::TAG_Float: {
- enum eCoreType dt;
- double v;
- s % dt;
- s.item( v );
- m_data = Token::Data::make_Float({dt, v});
- break; }
- case Token::Data::TAG_Fragment:
- assert(!"Serialising interpolated macro fragment");
- }
-});
::std::ostream& operator<<(::std::ostream& os, const Token& tok)
{
@@ -553,7 +493,7 @@ SERIALISE_TYPE(Token::, "Token", {
os << ":" << *reinterpret_cast<AST::ExprNode*>(tok.m_data.as_Fragment());
break;
case TOK_INTERPOLATED_META:
- os << ":" << *reinterpret_cast<AST::MetaItem*>(tok.m_data.as_Fragment());
+ os << ":" << *reinterpret_cast<AST::Attribute*>(tok.m_data.as_Fragment());
break;
case TOK_INTERPOLATED_ITEM: {
const auto& named_item = *reinterpret_cast<const AST::Named<AST::Item>*>(tok.m_data.as_Fragment());
diff --git a/src/parse/token.hpp b/src/parse/token.hpp
index 0ef8f009..3605679b 100644
--- a/src/parse/token.hpp
+++ b/src/parse/token.hpp
@@ -9,9 +9,9 @@
#include <rc_string.hpp>
#include <tagged_union.hpp>
-#include <serialise.hpp>
#include "../coretypes.hpp"
#include <ident.hpp>
+#include <memory>
enum eTokenType
{
@@ -47,7 +47,7 @@ namespace AST {
class Pattern;
class Path;
class ExprNode;
- class MetaItem;
+ class Attribute;
class Item;
template<typename T>
@@ -56,9 +56,11 @@ namespace AST {
class InterpolatedFragment;
-class Token:
- public Serialisable
+class Token
{
+ friend class HirSerialiser;
+ friend class HirDeserialiser;
+
TAGGED_UNION(Data, None,
(None, struct {}),
(String, ::std::string),
@@ -77,6 +79,12 @@ class Token:
Data m_data;
Position m_pos;
+ Token(enum eTokenType t, Data d, Position p):
+ m_type(t),
+ m_data( ::std::move(d) ),
+ m_pos( ::std::move(p) )
+ {
+ }
public:
virtual ~Token();
Token();
@@ -115,7 +123,7 @@ public:
TypeRef& frag_type() { assert(m_type == TOK_INTERPOLATED_TYPE); return *reinterpret_cast<TypeRef*>( m_data.as_Fragment() ); }
AST::Path& frag_path() { assert(m_type == TOK_INTERPOLATED_PATH); return *reinterpret_cast<AST::Path*>( m_data.as_Fragment() ); }
AST::Pattern& frag_pattern() { assert(m_type == TOK_INTERPOLATED_PATTERN); return *reinterpret_cast<AST::Pattern*>( m_data.as_Fragment() ); }
- AST::MetaItem& frag_meta() { assert(m_type == TOK_INTERPOLATED_META); return *reinterpret_cast<AST::MetaItem*>( m_data.as_Fragment() ); }
+ AST::Attribute& frag_meta() { assert(m_type == TOK_INTERPOLATED_META); return *reinterpret_cast<AST::Attribute*>( m_data.as_Fragment() ); }
::std::unique_ptr<AST::ExprNode> take_frag_node();
::AST::Named<AST::Item> take_frag_item();
@@ -141,8 +149,6 @@ public:
static const char* typestr(enum eTokenType type);
static eTokenType typefromstr(const ::std::string& s);
- SERIALISABLE_PROTOTYPES();
-
friend ::std::ostream& operator<<(::std::ostream& os, const Token& tok);
};
extern ::std::ostream& operator<<(::std::ostream& os, const Token& tok);
diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp
index 901312a3..611df2ff 100644
--- a/src/parse/tokenstream.cpp
+++ b/src/parse/tokenstream.cpp
@@ -140,8 +140,12 @@ Ident TokenStream::get_ident(Token tok) const
if(tok.type() == TOK_IDENT) {
return Ident(getHygiene(), tok.str());
}
+ else if(tok.type() == TOK_LIFETIME) {
+ // TODO: Maybe only when it's explicitly asked for?
+ return Ident(getHygiene(), tok.str());
+ }
else if( tok.type() == TOK_INTERPOLATED_IDENT ) {
- TODO(getPosition(), "");
+ TODO(getPosition(), "get_ident from TOK_INTERPOLATED_IDENT");
}
else {
throw ParseError::Unexpected(*this, tok);
diff --git a/src/parse/tokenstream.hpp b/src/parse/tokenstream.hpp
index 766e52bc..a9d325c2 100644
--- a/src/parse/tokenstream.hpp
+++ b/src/parse/tokenstream.hpp
@@ -16,7 +16,7 @@
namespace AST {
class Module;
- class MetaItems;
+ class AttributeList;
}
/// State the parser needs to pass down via a second channel.
@@ -28,7 +28,7 @@ struct ParseState
bool no_expand_macros = false;
::AST::Module* module = nullptr;
- ::AST::MetaItems* parent_attrs = nullptr;
+ ::AST::AttributeList* parent_attrs = nullptr;
::AST::Module& get_current_mod() {
assert(this->module);
diff --git a/src/parse/types.cpp b/src/parse/types.cpp
index 26785cf7..a07e66f8 100644
--- a/src/parse/types.cpp
+++ b/src/parse/types.cpp
@@ -13,8 +13,8 @@
// === PROTOTYPES ===
//TypeRef Parse_Type(TokenStream& lex, bool allow_trait_list);
TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list);
-TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls = {});
-TypeRef Parse_Type_Path(TokenStream& lex, ::std::vector<::std::string> hrls, bool allow_trait_list);
+TypeRef Parse_Type_Fn(TokenStream& lex, AST::HigherRankedBounds hrbs = {});
+TypeRef Parse_Type_Path(TokenStream& lex, AST::HigherRankedBounds hrbs, bool allow_trait_list);
TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list);
// === CODE ===
@@ -71,7 +71,6 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
case TOK_RWORD_UNSAFE:
case TOK_RWORD_EXTERN:
case TOK_RWORD_FN:
- // TODO: Handle HRLS in fn types
return Parse_Type_Fn(lex, hrls);
default:
return Parse_Type_Path(lex, hrls, true);
@@ -109,23 +108,21 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
lex.putback(Token(TOK_AMP));
// '&' - Reference type
case TOK_AMP: {
- ::std::string lifetime;
+ AST::LifetimeRef lifetime;
// Reference
tok = lex.getToken();
if( tok.type() == TOK_LIFETIME ) {
- lifetime = tok.str();
+ lifetime = AST::LifetimeRef(/*lex.point_span(), */lex.get_ident(::std::move(tok)));
tok = lex.getToken();
}
+ bool is_mut = false;
if( tok.type() == TOK_RWORD_MUT ) {
- // Mutable reference
- return TypeRef(TypeRef::TagReference(), lex.end_span(ps), true, Parse_Type(lex, false));
+ is_mut = true;
}
else {
PUTBACK(tok, lex);
- // Immutable reference
- return TypeRef(TypeRef::TagReference(), lex.end_span(ps), false, Parse_Type(lex, false));
}
- throw ParseError::BugCheck("Reached end of Parse_Type:AMP");
+ return TypeRef(TypeRef::TagReference(), lex.end_span(ps), ::std::move(lifetime), is_mut, Parse_Type(lex, false));
}
// '*' - Raw pointer
case TOK_STAR:
@@ -196,10 +193,9 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
throw ParseError::BugCheck("Reached end of Parse_Type");
}
-TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls)
+TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs)
{
auto ps = lex.start_span();
- // TODO: HRLs
TRACE_FUNCTION;
Token tok;
@@ -208,11 +204,13 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls)
GET_TOK(tok, lex);
+ // `unsafe`
if( tok.type() == TOK_RWORD_UNSAFE )
{
is_unsafe = true;
GET_TOK(tok, lex);
}
+ // `exern`
if( tok.type() == TOK_RWORD_EXTERN )
{
if( GET_TOK(tok, lex) == TOK_STRING ) {
@@ -225,6 +223,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls)
abi = "C";
}
}
+ // `fn`
CHECK_TOK(tok, TOK_RWORD_FN);
::std::vector<TypeRef> args;
@@ -250,6 +249,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls)
}
GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);
+ // `-> RetType`
TypeRef ret_type = TypeRef(TypeRef::TagUnit(), Span(tok.get_pos()));
if( GET_TOK(tok, lex) == TOK_THINARROW )
{
@@ -259,39 +259,55 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls)
PUTBACK(tok, lex);
}
- return TypeRef(TypeRef::TagFunction(), lex.end_span(ps), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type));
+ return TypeRef(TypeRef::TagFunction(), lex.end_span(ps), mv$(hrbs), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type));
}
-TypeRef Parse_Type_Path(TokenStream& lex, ::std::vector<::std::string> hrls, bool allow_trait_list)
+TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool allow_trait_list)
{
Token tok;
auto ps = lex.start_span();
- if( ! allow_trait_list )
+ if( hrbs.empty() && !allow_trait_list )
{
return TypeRef(TypeRef::TagPath(), lex.end_span(ps), Parse_Path(lex, PATH_GENERIC_TYPE));
}
else
{
- ::std::vector<AST::Path> traits;
- ::std::vector< ::std::string> lifetimes;
- do {
- if( LOOK_AHEAD(lex) == TOK_LIFETIME ) {
- GET_TOK(tok, lex);
- lifetimes.push_back( tok.str() );
+ ::std::vector<Type_TraitPath> traits;
+ ::std::vector<AST::LifetimeRef> lifetimes;
+
+ traits.push_back(Type_TraitPath { mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
+
+ if( allow_trait_list )
+ {
+ while( GET_TOK(tok, lex) == TOK_PLUS )
+ {
+ if( LOOK_AHEAD(lex) == TOK_LIFETIME ) {
+ GET_TOK(tok, lex);
+ lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) ));
+ }
+ else
+ {
+ if( lex.lookahead(0) == TOK_RWORD_FOR )
+ {
+ hrbs = Parse_HRB(lex);
+ }
+ traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
+ }
}
- else
- traits.push_back( Parse_Path(lex, PATH_GENERIC_TYPE) );
- } while( GET_TOK(tok, lex) == TOK_PLUS );
- PUTBACK(tok, lex);
- if( hrls.size() > 0 || traits.size() > 1 || lifetimes.size() > 0 ) {
- if( lifetimes.size() )
- DEBUG("TODO: Lifetime bounds on trait objects");
- return TypeRef(lex.end_span(ps), mv$(hrls), ::std::move(traits));
+ PUTBACK(tok, lex);
}
- else {
- return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(traits.at(0)));
+
+ if( !traits[0].hrbs.empty() || traits.size() > 1 || lifetimes.size() > 0 )
+ {
+ if( lifetimes.empty())
+ lifetimes.push_back(AST::LifetimeRef());
+ return TypeRef(lex.end_span(ps), mv$(traits), mv$(lifetimes));
+ }
+ else
+ {
+ return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(traits.at(0).path));
}
}
}
@@ -300,20 +316,25 @@ TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list)
Token tok;
auto ps = lex.start_span();
- ::std::vector<AST::Path> traits;
- ::std::vector< ::std::string> lifetimes;
+ ::std::vector<Type_TraitPath> traits;
+ ::std::vector<AST::LifetimeRef> lifetimes;
do {
if( LOOK_AHEAD(lex) == TOK_LIFETIME ) {
GET_TOK(tok, lex);
- lifetimes.push_back( tok.str() );
+ lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) ));
}
else
- traits.push_back( Parse_Path(lex, PATH_GENERIC_TYPE) );
+ {
+ AST::HigherRankedBounds hrbs;
+ if( lex.lookahead(0) == TOK_RWORD_FOR )
+ {
+ hrbs = Parse_HRB(lex);
+ }
+ traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
+ }
} while( GET_TOK(tok, lex) == TOK_PLUS );
PUTBACK(tok, lex);
- if( lifetimes.size() )
- DEBUG("TODO: Lifetime bounds on erased types");
- return TypeRef(lex.end_span(ps), TypeData::make_ErasedType({ {}, mv$(traits) }));
+ return TypeRef(lex.end_span(ps), TypeData::make_ErasedType({ mv$(traits), mv$(lifetimes) }));
}
diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp
index aece0032..c51cac72 100644
--- a/src/resolve/absolute.cpp
+++ b/src/resolve/absolute.cpp
@@ -20,6 +20,7 @@ namespace
{
Top,
Method,
+ Hrb,
} level;
unsigned short index;
@@ -38,6 +39,12 @@ namespace
::std::string name;
Val value;
};
+ template<typename Val>
+ struct NamedI
+ {
+ const Ident& name;
+ Val value;
+ };
struct Context
{
@@ -55,7 +62,7 @@ namespace
// Map of names to slots
::std::vector< Named< GenericSlot > > types;
::std::vector< Named< GenericSlot > > constants;
- ::std::vector< Named< GenericSlot > > lifetimes;
+ ::std::vector< NamedI< GenericSlot > > lifetimes;
})
);
@@ -74,6 +81,17 @@ namespace
m_frozen_bind_set( false )
{}
+ void push(const ::AST::HigherRankedBounds& params) {
+ auto e = Ent::make_Generic({});
+ auto& data = e.as_Generic();
+
+ for(size_t i = 0; i < params.m_lifetimes.size(); i ++)
+ {
+ data.lifetimes.push_back( NamedI<GenericSlot> { params.m_lifetimes[i].name(), GenericSlot { GenericSlot::Level::Hrb, static_cast<unsigned short>(i) } } );
+ }
+
+ m_name_context.push_back(mv$(e));
+ }
void push(const ::AST::GenericParams& params, GenericSlot::Level level, bool has_self=false) {
auto e = Ent::make_Generic({});
auto& data = e.as_Generic();
@@ -85,16 +103,24 @@ namespace
}
if( params.ty_params().size() > 0 ) {
const auto& typs = params.ty_params();
- for(unsigned int i = 0; i < typs.size(); i ++ ) {
+ for(size_t i = 0; i < typs.size(); i ++ ) {
data.types.push_back( Named<GenericSlot> { typs[i].name(), GenericSlot { level, static_cast<unsigned short>(i) } } );
}
}
if( params.lft_params().size() > 0 ) {
- //TODO(Span(), "resolve/absolute.cpp - Context::push(GenericParams) - Lifetime params - " << params);
+ const auto& lfts = params.lft_params();
+ for(size_t i = 0; i < lfts.size(); i ++ ) {
+ data.lifetimes.push_back( NamedI<GenericSlot> { lfts[i].name(), GenericSlot { level, static_cast<unsigned short>(i) } } );
+ }
}
m_name_context.push_back(mv$(e));
}
+ void pop(const ::AST::HigherRankedBounds& ) {
+ if( !m_name_context.back().is_Generic() )
+ BUG(Span(), "resolve/absolute.cpp - Context::pop(GenericParams) - Mismatched pop");
+ m_name_context.pop_back();
+ }
void pop(const ::AST::GenericParams& , bool has_self=false) {
if( !m_name_context.back().is_Generic() )
BUG(Span(), "resolve/absolute.cpp - Context::pop(GenericParams) - Mismatched pop");
@@ -501,6 +527,7 @@ namespace
void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Context::LookupMode& mode, ::AST::Path& path);
void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::LookupMode mode, ::AST::Path& path);
+void Resolve_Absolute_Lifetime(Context& context, const Span& sp, AST::LifetimeRef& type);
void Resolve_Absolute_Type(Context& context, TypeRef& type);
void Resolve_Absolute_Expr(Context& context, ::AST::Expr& expr);
void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node);
@@ -714,7 +741,7 @@ namespace {
TU_MATCH(::HIR::ValueItem, (it->second->ent), (e),
(Import,
// Wait? is this even valid?
- TODO(sp, "HIR Import item pointed to an import");
+ BUG(sp, "HIR Import item pointed to an import");
),
(Constant,
pb = ::AST::PathBinding::make_Static({nullptr, nullptr});
@@ -741,7 +768,7 @@ namespace {
TU_MATCH(::HIR::TypeItem, (it->second->ent), (e),
(Import,
// Wait? is this even valid?
- TODO(sp, "HIR Import item pointed to an import");
+ BUG(sp, "HIR Import item pointed to an import");
),
(Module,
pb = ::AST::PathBinding::make_Module({nullptr, &e});
@@ -787,7 +814,7 @@ namespace {
path.bind( ::AST::PathBinding::make_Module({nullptr, &crate.m_hir->m_root_module}) );
return ;
default:
- TODO(sp, "");
+ TODO(sp, "Looking up a non-namespace, but pointed to crate root");
}
}
@@ -1180,7 +1207,6 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex
),
(Module,
if( name_ref.is_import ) {
- //TODO(sp, "Replace path component with new path - " << path << "[.."<<i+1<<"] with " << name_ref.path);
auto newpath = name_ref.path;
for(unsigned int j = i+1; j < path_abs.nodes.size(); j ++)
{
@@ -1304,8 +1330,6 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
}
if( !found )
{
- //TODO(sp, "Switch back to primitive from " << p << " for " << path);
- //p = ::AST::Path( ::AST::Path::TagLocal(), e.nodes[0].name() );
auto ct = coretype_fromstring(e.nodes[0].name());
p = ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(Span("-",0,0,0,0), ct), ::AST::Path(), ::std::vector< ::AST::PathNode>() );
}
@@ -1435,6 +1459,37 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
// - Helps with cases like PartialOrd<Self>, but hinders when the default is a hint (in expressions)
}
+void Resolve_Absolute_Lifetime(Context& context, const Span& sp, AST::LifetimeRef& lft)
+{
+ TRACE_FUNCTION_FR("lft = " << lft, "lft = " << lft);
+ if( lft.is_unbound() )
+ {
+ if( lft.name() == "static" )
+ {
+ lft = AST::LifetimeRef::new_static();
+ return ;
+ }
+
+ for(auto it = context.m_name_context.rbegin(); it != context.m_name_context.rend(); ++ it)
+ {
+ if( const auto* e = it->opt_Generic() )
+ {
+ for(const auto& l : e->lifetimes)
+ {
+ // NOTE: Hygiene doesn't apply to lifetime params!
+ if( l.name.name == lft.name().name /*&& l.name.hygiene.is_visible(lft.name().hygiene)*/ )
+ {
+ lft.set_binding( l.value.index | (static_cast<int>(l.value.level) << 8) );
+ return ;
+ }
+ }
+ }
+ }
+
+ ERROR(sp, E0000, "Couldn't find lifetime " << lft);
+ }
+}
+
void Resolve_Absolute_Type(Context& context, TypeRef& type)
{
TRACE_FUNCTION_FR("type = " << type, "type = " << type);
@@ -1457,16 +1512,19 @@ void Resolve_Absolute_Type(Context& context, TypeRef& type)
(Primitive,
),
(Function,
+ context.push( e.info.hrbs );
Resolve_Absolute_Type(context, *e.info.m_rettype);
for(auto& t : e.info.m_arg_types) {
Resolve_Absolute_Type(context, t);
}
+ context.pop( e.info.hrbs );
),
(Tuple,
for(auto& t : e.inner_types)
Resolve_Absolute_Type(context, t);
),
(Borrow,
+ Resolve_Absolute_Lifetime(context, type.span(), e.lifetime);
Resolve_Absolute_Type(context, *e.inner);
),
(Pointer,
@@ -1503,24 +1561,28 @@ void Resolve_Absolute_Type(Context& context, TypeRef& type)
)
TU_IFLET(::AST::PathBinding, e.path.binding(), Trait, be,
- auto ty = ::TypeRef( type.span(), {}, ::make_vec1(mv$(e.path)) );
+ auto ty = ::TypeRef( type.span(), ::make_vec1(Type_TraitPath { {}, mv$(e.path)}), {} );
type = mv$(ty);
return ;
)
),
(TraitObject,
- //context.push_lifetimes( e.hrls );
for(auto& trait : e.traits) {
- Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, trait);
+ context.push( trait.hrbs );
+ Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, trait.path);
+ context.pop(trait.hrbs);
}
- //context.pop_lifetimes();
+ for(auto& lft : e.lifetimes)
+ Resolve_Absolute_Lifetime(context, type.span(),lft);
),
(ErasedType,
- //context.push_lifetimes( e.hrls );
for(auto& trait : e.traits) {
- Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, trait);
+ context.push( trait.hrbs );
+ Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, trait.path);
+ context.pop(trait.hrbs);
}
- //context.pop_lifetimes();
+ for(auto& lft : e.lifetimes)
+ Resolve_Absolute_Lifetime(context, type.span(), lft);
)
)
}
@@ -1686,15 +1748,23 @@ void Resolve_Absolute_Generic(Context& context, ::AST::GenericParams& params)
for( auto& bound : params.bounds() )
{
TU_MATCH(::AST::GenericBound, (bound), (e),
+ (None,
+ ),
(Lifetime,
- // TODO: Link lifetime names to params
+ Resolve_Absolute_Lifetime(context, bound.span, e.test);
+ Resolve_Absolute_Lifetime(context, bound.span,e.bound);
),
(TypeLifetime,
Resolve_Absolute_Type(context, e.type);
+ Resolve_Absolute_Lifetime(context, bound.span, e.bound);
),
(IsTrait,
+ context.push( e.outer_hrbs );
Resolve_Absolute_Type(context, e.type);
+ context.push( e.inner_hrbs );
Resolve_Absolute_Path(context, bound.span, Context::LookupMode::Type, e.trait);
+ context.pop( e.inner_hrbs );
+ context.pop( e.outer_hrbs );
),
(MaybeTrait,
Resolve_Absolute_Type(context, e.type);
@@ -1739,11 +1809,11 @@ void Resolve_Absolute_Pattern(Context& context, bool allow_refutable, ::AST::Pa
auto p = context.lookup_opt( name.name, name.hygiene, Context::LookupMode::PatternValue );
if( p.is_valid() ) {
Resolve_Absolute_Path(context, pat.span(), Context::LookupMode::PatternValue, p);
- pat = ::AST::Pattern(::AST::Pattern::TagValue(), ::AST::Pattern::Value::make_Named(mv$(p)));
+ pat = ::AST::Pattern(::AST::Pattern::TagValue(), pat.span(), ::AST::Pattern::Value::make_Named(mv$(p)));
DEBUG("MaybeBind resolved to " << pat);
}
else {
- pat = ::AST::Pattern(::AST::Pattern::TagBind(), mv$(name));
+ pat = ::AST::Pattern(::AST::Pattern::TagBind(), pat.span(), mv$(name));
pat.binding().m_slot = context.push_var( pat.span(), pat.binding().m_name );
DEBUG("- Binding #" << pat.binding().m_slot << " '" << pat.binding().m_name << "' (was MaybeBind)");
}
@@ -1751,7 +1821,7 @@ void Resolve_Absolute_Pattern(Context& context, bool allow_refutable, ::AST::Pa
else {
auto name = mv$( e.name );
- pat = ::AST::Pattern(::AST::Pattern::TagBind(), mv$(name));
+ pat = ::AST::Pattern(::AST::Pattern::TagBind(), pat.span(), mv$(name));
pat.binding().m_slot = context.push_var( pat.span(), pat.binding().m_name );
}
),
@@ -1769,7 +1839,10 @@ void Resolve_Absolute_Pattern(Context& context, bool allow_refutable, ::AST::Pa
),
(Value,
if( ! allow_refutable )
+ {
+ // TODO: If this is a single value of a unit-like struct, accept
BUG(pat.span(), "Resolve_Absolute_Pattern - Encountered refutable pattern where only irrefutable allowed - " << pat);
+ }
Resolve_Absolute_PatternValue(context, pat.span(), e.start);
Resolve_Absolute_PatternValue(context, pat.span(), e.end);
),
@@ -1985,12 +2058,14 @@ void Resolve_Absolute_Trait(Context& item_context, ::AST::Trait& e)
Resolve_Absolute_Generic(item_context, e.params());
for(auto& st : e.supertraits()) {
- if( !st.ent.is_valid() ) {
+ if( !st.ent.path.is_valid() ) {
DEBUG("- ST 'static");
}
else {
- DEBUG("- ST " << st.ent);
- Resolve_Absolute_Path(item_context, st.sp, Context::LookupMode::Type, st.ent);
+ DEBUG("- ST " << st.ent.hrbs << st.ent.path);
+ item_context.push(st.ent.hrbs);
+ Resolve_Absolute_Path(item_context, st.sp, Context::LookupMode::Type, st.ent.path);
+ item_context.pop(st.ent.hrbs);
}
}
@@ -2072,7 +2147,7 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod )
Resolve_Absolute_Path(item_context, def.trait().sp, Context::LookupMode::Type, def.trait().ent);
if( e.items().size() != 0 ) {
- ERROR(def.span(), E0000, "impl Trait for .. with methods");
+ ERROR(i.data.span, E0000, "impl Trait for .. with methods");
}
item_context.pop(def.params());
@@ -2105,7 +2180,7 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod )
Resolve_Absolute_Type(item_context, impl_def.type());
if( !impl_def.trait().ent.is_valid() )
- BUG(impl_def.span(), "Encountered negative impl with no trait");
+ BUG(i.data.span, "Encountered negative impl with no trait");
Resolve_Absolute_Path(item_context, impl_def.trait().sp, Context::LookupMode::Type, impl_def.trait().ent);
// No items
diff --git a/src/serialise.cpp b/src/serialise.cpp
deleted file mode 100644
index e79d4025..00000000
--- a/src/serialise.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- */
-#define DISABLE_DEBUG
-#include <serialise.hpp>
-#include <serialiser_texttree.hpp>
-#include "common.hpp"
-
-Serialiser& Serialiser::operator<<(const Serialisable& subobj)
-{
- start_object(subobj.serialise_tag());
- subobj.serialise(*this);
- end_object(subobj.serialise_tag());
- return *this;
-}
-
-void Deserialiser::item(Serialisable& s)
-{
- DEBUG("Deserialise - '"<<s.serialise_tag()<<"'");
- start_object(s.serialise_tag());
- s.deserialise(*this);
- end_object(s.serialise_tag());
-}
-::std::string Deserialiser::start_object()
-{
- ::std::string s = read_tag();
- DEBUG("tag = '" << s << "'");
- start_object(nullptr);
- return s;
-}
-
-
-// --------------------------------------------------------------------
-Serialiser_TextTree::Serialiser_TextTree(::std::ostream& os):
- m_os(os),
- m_indent_level(0),
- m_array_was_empty(false)
-{
-}
-
-void Serialiser_TextTree::start_object(const char *tag) {
- print_indent();
- m_os << tag << " {\n";
- indent();
-}
-void Serialiser_TextTree::end_object(const char * /*tag*/) {
- unindent();
- print_indent();
- m_os << "}\n";
-}
-void Serialiser_TextTree::start_array(unsigned int size) {
- print_indent();
- if( size == 0 ) {
- m_os << "[]\n";
- m_array_was_empty = true;
- }
- else {
- m_os << "[" << size << "\n";
- indent();
- }
-}
-void Serialiser_TextTree::end_array() {
- if( m_array_was_empty ) {
- m_array_was_empty = false;
- }
- else {
- unindent();
- print_indent();
- m_os << "]\n";
- }
-}
-Serialiser& Serialiser_TextTree::operator<<(bool val)
-{
- print_indent();
- m_os << (val ? "T" : "F") << "\n";
- return *this;
-}
-Serialiser& Serialiser_TextTree::operator<<(uint64_t val)
-{
- print_indent();
- m_os << val << "\n";
- return *this;
-}
-Serialiser& Serialiser_TextTree::operator<<(int64_t val)
-{
- print_indent();
- m_os << val << "\n";
- return *this;
-}
-Serialiser& Serialiser_TextTree::operator<<(double val)
-{
- print_indent();
- m_os << val << "\n";
- return *this;
-}
-
-Serialiser& Serialiser_TextTree::operator<<(const char* s)
-{
- print_indent();
- m_os << "\"" << s << "\"\n";
- return *this;
-}
-void Serialiser_TextTree::indent()
-{
- m_indent_level ++;
-}
-void Serialiser_TextTree::unindent()
-{
- m_indent_level --;
-}
-void Serialiser_TextTree::print_indent()
-{
- for(int i = 0; i < m_indent_level; i ++)
- m_os << " ";
-}
-
-// --------------------------------------------------------------------
-Deserialiser_TextTree::Deserialiser_TextTree(::std::istream& is):
- m_is(is)
-{
-}
-bool Deserialiser_TextTree::is_ws(char c)
-{
- return c == ' ' || c == '\t' || c == '\n' || c == '\r';
-}
-char Deserialiser_TextTree::getc()
-{
- char c;
- m_is.get(c);
- return c;
-}
-char Deserialiser_TextTree::peekc()
-{
- return m_is.peek();
-}
-void Deserialiser_TextTree::eat_ws()
-{
- char c;
- do {
- m_is.get(c);
- } while( is_ws(c) );
- m_is.putback(c);
-}
-size_t Deserialiser_TextTree::start_array()
-{
- eat_ws();
- char c = getc();
- if( c != '[' )
- throw DeserialiseFailure("start_array", "no [");
-
- eat_ws();
- if( peekc() == ']' ) {
- DEBUG("len = 0");
- return 0;
- }
-
- size_t len;
- m_is >> len;
- if( !m_is.good() )
- throw DeserialiseFailure("start_array", "length missing");
- DEBUG("len = "<<len);
- return len;
-}
-void Deserialiser_TextTree::end_array()
-{
- eat_ws();
- char c = getc();
- DEBUG("c = '"<<c<<"'");
- if( c != ']' )
- throw DeserialiseFailure("end_array", "no ]");
-}
-::std::string Deserialiser_TextTree::read_tag()
-{
- ::std::string tag;
- eat_ws();
- char c;
- do {
- m_is.get(c);
- tag.push_back(c);
- } while( !is_ws(c) );
- tag.pop_back();
- if( tag.size() == 0 )
- throw DeserialiseFailure("read_tag", "tag empty");
- return tag;
-}
-
-void Deserialiser_TextTree::item(bool& b)
-{
- eat_ws();
- switch( getc() )
- {
- case 'T': DEBUG("true"); b = true; break;
- case 'F': DEBUG("false"); b = false; break;
- default:
- throw DeserialiseFailure("item(bool)", "bad value");
- }
-}
-void Deserialiser_TextTree::item(uint64_t& v)
-{
- eat_ws();
- m_is >> v;
- if( !m_is.good() )
- throw DeserialiseFailure("item(uint64_t)", "bad value");
-}
-void Deserialiser_TextTree::item(int64_t& v)
-{
- eat_ws();
- m_is >> v;
- if( !m_is.good() )
- throw DeserialiseFailure("item(int64_t)", "bad value");
-}
-void Deserialiser_TextTree::item(double& v)
-{
- eat_ws();
- m_is >> v;
- if( !m_is.good() )
- throw DeserialiseFailure("item(double)", "bad value");
-}
-void Deserialiser_TextTree::item(::std::string& s)
-{
- eat_ws();
-
- ::std::string rv;
- char c = getc();
- DEBUG("c = '"<<c<<"'");
- if( c != '"' )
- throw DeserialiseFailure("item(::std::string)", "no open \"");
-
- while(peekc() != '"')
- {
- char c = getc();
- if( c == '\\' )
- c = getc();
- rv.push_back(c);
- }
- getc(); // eat "
-
- DEBUG("rv = '"<<rv<<"'");
- s = rv;
-}
-
-void Deserialiser_TextTree::start_object(const char *tag)
-{
- eat_ws();
- if( tag != nullptr ) {
- ::std::string s = read_tag();
- DEBUG("s == " << s);
- if( s != tag )
- throw DeserialiseFailure("start_object", "tag mismatch");
- }
- eat_ws();
- char c = getc();
- DEBUG("c = '" << c << "' (tag = " << (tag ? tag : "-NUL-"));
- if( c != '{' )
- throw DeserialiseFailure("start_object", "no {");
-}
-void Deserialiser_TextTree::end_object(const char * /*tag*/)
-{
- eat_ws();
- char c = getc();
- DEBUG("c = '"<<c<<"'");
- if( c != '}' ) {
- throw DeserialiseFailure("end_object", "no }");
- }
-}
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 5df20334..c30657bf 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -196,6 +196,7 @@ namespace {
} m_options;
::std::vector< ::std::pair< ::HIR::GenericPath, const ::HIR::Struct*> > m_box_glue_todo;
+ ::std::set< ::HIR::TypeRef> m_emitted_fn_types;
public:
CodeGenerator_C(const ::HIR::Crate& crate, const ::std::string& outfile):
m_crate(crate),
@@ -204,7 +205,7 @@ namespace {
m_outfile_path_c(outfile + ".c"),
m_of(m_outfile_path_c)
{
- switch(Target_GetCurSpec().m_codegen_mode)
+ switch(Target_GetCurSpec().m_backend_c.m_codegen_mode)
{
case CodegenMode::Gnu11:
m_compiler = Compiler::Gcc;
@@ -302,7 +303,7 @@ namespace {
<< "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n"
<< "}\n"
;
- break;
+ break;
case Compiler::Msvc:
m_of
<< "static inline uint64_t __builtin_popcount(uint64_t v) {\n"
@@ -510,6 +511,7 @@ namespace {
emit_box_drop_glue( mv$(e.first), *e.second );
}
+ // TODO: Define this function in MIR.
if( is_executable )
{
m_of << "int main(int argc, const char* argv[]) {\n";
@@ -565,7 +567,7 @@ namespace {
// - `gcc-${TRIPLE}` (if available)
// - `gcc` as fallback
{
- ::std::string varname = "CC-" + Target_GetCurSpec().m_c_compiler;
+ ::std::string varname = "CC-" + Target_GetCurSpec().m_backend_c.m_c_compiler;
if( getenv(varname.c_str()) ) {
args.push_back( getenv(varname.c_str()) );
}
@@ -574,12 +576,14 @@ namespace {
}
else {
// TODO: Determine if the compiler can't be found, and fall back to `gcc` if that's the case
- args.push_back( Target_GetCurSpec().m_c_compiler + "-gcc" );
+ args.push_back( Target_GetCurSpec().m_backend_c.m_c_compiler + "-gcc" );
//args.push_back( "gcc" );
}
}
- args.push_back("-ffunction-sections");
- args.push_back("-pthread");
+ for( const auto& a : Target_GetCurSpec().m_backend_c.m_compiler_opts )
+ {
+ args.push_back( a.c_str() );
+ }
switch(opt.opt_level)
{
case 0: break;
@@ -622,7 +626,10 @@ namespace {
{
args.push_back("-l"); args.push_back(path.c_str());
}
- args.push_back("-Wl,--gc-sections");
+ for( const auto& a : Target_GetCurSpec().m_backend_c.m_linker_opts )
+ {
+ args.push_back( a.c_str() );
+ }
}
else
{
@@ -631,8 +638,9 @@ namespace {
break;
case Compiler::Msvc:
// TODO: Look up these paths in the registry and use CreateProcess instead of system
+ // - OR, run `vcvarsall` and get the required environment variables and PATH from it?
args.push_back(detect_msvc().path_vcvarsall);
- args.push_back( Target_GetCurSpec().m_c_compiler );
+ args.push_back( Target_GetCurSpec().m_backend_c.m_c_compiler );
args.push_back("&");
args.push_back("cl.exe");
args.push_back("/nologo");
@@ -678,9 +686,9 @@ namespace {
}
args.push_back("kernel32.lib"); // Needed for Interlocked*
- // Command-line specified linker search directories
args.push_back("/link");
- //args.push_back("/verbose");
+
+ // Command-line specified linker search directories
for(const auto& path : link_dirs )
{
args.push_back(FMT("/LIBPATH:" << path));
@@ -818,6 +826,11 @@ namespace {
}
void emit_type_fn(const ::HIR::TypeRef& ty)
{
+ if( m_emitted_fn_types.count(ty) ) {
+ return ;
+ }
+ m_emitted_fn_types.insert(ty.clone());
+
const auto& te = ty.m_data.as_Function();
m_of << "typedef ";
// TODO: ABI marker, need an ABI enum?
@@ -1127,6 +1140,12 @@ namespace {
m_of << ".PTR";
}
}
+ else if( const auto* te = ty->m_data.opt_Pointer() )
+ {
+ if( metadata_type(*te->inner) != MetadataType::None ) {
+ m_of << ".PTR";
+ }
+ }
}
void emit_enum(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Enum& item) override
@@ -3556,7 +3575,7 @@ namespace {
#endif
}
- if( Target_GetCurSpec().m_c_compiler == "amd64" ) {
+ if( Target_GetCurSpec().m_backend_c.m_c_compiler == "amd64" ) {
MIR_TODO(mir_res, "MSVC amd64 doesn't support inline assembly, need to have a transform for '" << e.tpl << "'");
}
m_of << indent << "__asm {\n";
@@ -4664,6 +4683,11 @@ namespace {
void emit_destructor_call(const ::MIR::LValue& slot, const ::HIR::TypeRef& ty, bool unsized_valid, unsigned indent_level)
{
+ // If the type doesn't need dropping, don't try.
+ if( !m_resolve.type_needs_drop_glue(sp, ty) )
+ {
+ return ;
+ }
auto indent = RepeatLitStr { "\t", static_cast<int>(indent_level) };
TU_MATCHA( (ty.m_data), (te),
// Impossible
diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp
index faa3598d..3347606c 100644
--- a/src/trans/codegen_mmir.cpp
+++ b/src/trans/codegen_mmir.cpp
@@ -157,7 +157,7 @@ namespace
{
if( is_executable )
{
- m_of << "fn ::main#(i32, *const *const i8): i32 {\n";
+ m_of << "fn ::main#(isize, *const *const i8): isize {\n";
auto c_start_path = m_resolve.m_crate.get_lang_item_path_opt("mrustc-start");
if( c_start_path == ::HIR::SimplePath() )
{
@@ -281,6 +281,7 @@ namespace
case ::HIR::StructMarkings::DstType::TraitObject:
return MetadataType::TraitObject;
}
+ throw "";
} break;
TU_ARM(te.binding, Union, tpb)
return MetadataType::None;
@@ -433,6 +434,43 @@ namespace
}
m_mir_res = nullptr;
}
+ void emit_constructor_struct(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Struct& item) override
+ {
+ TRACE_FUNCTION_F(p);
+ ::HIR::TypeRef tmp;
+ auto monomorph = [&](const auto& x)->const auto& {
+ if( monomorphise_type_needed(x) ) {
+ tmp = monomorphise_type(sp, item.m_params, p.m_params, x);
+ m_resolve.expand_associated_types(sp, tmp);
+ return tmp;
+ }
+ else {
+ return x;
+ }
+ };
+ // Crate constructor function
+ const auto& e = item.m_data.as_Tuple();
+ m_of << "fn " << p << "(";
+ for(unsigned int i = 0; i < e.size(); i ++)
+ {
+ if(i != 0)
+ m_of << ", ";
+ m_of << monomorph(e[i].ent);
+ }
+ m_of << "): " << p << " {\n";
+ m_of << "\t0: {\n";
+ m_of << "\t\tASSIGN RETURN = { ";
+ for(unsigned int i = 0; i < e.size(); i ++)
+ {
+ if(i != 0)
+ m_of << ", ";
+ m_of << "arg" << i;
+ }
+ m_of << " }: " << p << ";\n";
+ m_of << "\t\tRETURN\n";
+ m_of << "\t}\n";
+ m_of << "}\n";
+ }
void emit_union(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Union& item) override
{
::MIR::Function empty_fcn;
@@ -452,7 +490,7 @@ namespace
}
for(const auto& e : repr->fields)
{
- m_of << "\t" << "#" << (&e - repr->fields.data()) << ";\n";
+ m_of << "\t" << "#" << (&e - repr->fields.data()) << " =" << (&e - repr->fields.data()) << ";\n";
}
m_of << "}\n";
@@ -605,47 +643,50 @@ namespace
const ::HIR::Path* p;
::std::string bytes;
};
+ void emit_str_byte(uint8_t b) {
+ if( b == 0 ) {
+ m_of << "\\0";
+ }
+ else if( b == '\\' ) {
+ m_of << "\\\\";
+ }
+ else if( b == '"' ) {
+ m_of << "\\\"";
+ }
+ else if( ' ' <= b && b <= 'z' && b != '\\' ) {
+ m_of << b;
+ }
+ else if( b < 16 ) {
+ m_of << "\\x0" << ::std::hex << int(b) << ::std::dec;
+ }
+ else {
+ m_of << "\\x" << ::std::hex << int(b) << ::std::dec;
+ }
+ }
+ void emit_str_u32(uint32_t v) {
+ emit_str_byte(v & 0xFF);
+ emit_str_byte(v >> 8);
+ emit_str_byte(v >> 16);
+ emit_str_byte(v >> 24);
+ }
+ void emit_str_usize(uint64_t v) {
+ if( Target_GetCurSpec().m_arch.m_pointer_bits == 64 ) {
+ emit_str_u32(v );
+ emit_str_u32(v >> 32);
+ }
+ else if( Target_GetCurSpec().m_arch.m_pointer_bits == 64 ) {
+ emit_str_u32(v );
+ }
+ else {
+ emit_str_u32(v );
+ }
+ }
void emit_literal_as_bytes(const ::HIR::Literal& lit, const ::HIR::TypeRef& ty, ::std::vector<Reloc>& out_relocations, size_t base_ofs)
{
TRACE_FUNCTION_F(lit << ", " << ty);
- auto putb = [&](uint8_t b) {
- if( b == 0 ) {
- m_of << "\\0";
- }
- else if( b == '\\' ) {
- m_of << "\\\\";
- }
- else if( b == '"' ) {
- m_of << "\\\"";
- }
- else if( ' ' <= b && b <= 'z' && b != '\\' ) {
- m_of << b;
- }
- else if( b < 16 ) {
- m_of << "\\x0" << ::std::hex << int(b) << ::std::dec;
- }
- else {
- m_of << "\\x" << ::std::hex << int(b) << ::std::dec;
- }
- };
- auto putu32 = [&](uint32_t v) {
- putb(v & 0xFF);
- putb(v >> 8);
- putb(v >> 16);
- putb(v >> 24);
- };
- auto putsize = [&](uint64_t v) {
- if( Target_GetCurSpec().m_arch.m_pointer_bits == 64 ) {
- putu32(v );
- putu32(v >> 32);
- }
- else if( Target_GetCurSpec().m_arch.m_pointer_bits == 64 ) {
- putu32(v );
- }
- else {
- putu32(v );
- }
- };
+ auto putb = [&](uint8_t b) { emit_str_byte(b); };
+ auto putu32 = [&](uint32_t v) { emit_str_u32(v); };
+ auto putsize = [&](uint64_t v) { emit_str_usize(v); };
switch(ty.m_data.tag())
{
case ::HIR::TypeRef::Data::TAGDEAD: throw "";
@@ -877,6 +918,69 @@ namespace
m_mir_res = nullptr;
}
+ void emit_vtable(const ::HIR::Path& p, const ::HIR::Trait& trait) override
+ {
+ ::MIR::Function empty_fcn;
+ ::MIR::TypeResolve top_mir_res { sp, m_resolve, FMT_CB(ss, ss << "vtable " << p;), ::HIR::TypeRef(), {}, empty_fcn };
+
+ const size_t ptr_size = Target_GetCurSpec().m_arch.m_pointer_bits / 8;
+ const auto& trait_path = p.m_data.as_UfcsKnown().trait;
+ const auto& type = *p.m_data.as_UfcsKnown().type;
+
+ ::HIR::TypeRef vtable_ty;
+ {
+ auto vtable_sp = trait_path.m_path;
+ vtable_sp.m_components.back() += "#vtable";
+ auto vtable_params = trait_path.m_params.clone();
+ for(const auto& ty : trait.m_type_indexes) {
+ auto aty = ::HIR::TypeRef( ::HIR::Path( type.clone(), trait_path.clone(), ty.first ) );
+ m_resolve.expand_associated_types(sp, aty);
+ vtable_params.m_types.push_back( mv$(aty) );
+ }
+ const auto& vtable_ref = m_crate.get_struct_by_path(sp, vtable_sp);
+ vtable_ty = ::HIR::TypeRef( ::HIR::GenericPath(mv$(vtable_sp), mv$(vtable_params)), &vtable_ref );
+ }
+
+ size_t size, align;
+ MIR_ASSERT(*m_mir_res, Target_GetSizeAndAlignOf(sp, m_resolve, type, size, align), "Unexpected generic? " << type);
+ m_of << "static " << p << ": " << vtable_ty << " = \"";
+ // - Data
+ // Drop
+ emit_str_usize(0);
+ // Align
+ emit_str_usize(align);
+ // Size
+ emit_str_usize(size);
+ // Methods
+ for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ )
+ {
+ emit_str_usize(0);
+ }
+ m_of << "\" {";
+
+ // - Relocations
+ auto monomorph_cb_trait = monomorphise_type_get_cb(sp, &type, &trait_path.m_params, nullptr);
+ // Drop
+ // - TODO: Some types don't have drop glue
+ m_of << "@0+" << ptr_size << " = " << ::HIR::Path(type.clone(), "drop_glue#") << ", ";
+ // Methods
+ for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ )
+ {
+ // Find the corresponding vtable entry
+ for(const auto& m : trait.m_value_indexes)
+ {
+ if( m.second.first != 3+i )
+ continue ;
+
+ //MIR_ASSERT(*m_mir_res, tr.m_values.at(m.first).is_Function(), "TODO: Handle generating vtables with non-function items");
+ DEBUG("- " << m.second.first << " = " << m.second.second << " :: " << m.first);
+
+ auto gpath = monomorphise_genericpath_with(sp, m.second.second, monomorph_cb_trait, false);
+ m_of << "@" << (3 + i) * ptr_size << "+" << ptr_size << " = " << ::HIR::Path(type.clone(), mv$(gpath), m.first) << ", ";
+ }
+ }
+ m_of << "};\n";
+ }
void emit_function_ext(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) override
{
::MIR::Function empty_fcn;
@@ -915,6 +1019,12 @@ namespace
::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << p;), ret_type, arg_types, *code };
m_mir_res = &mir_res;
+ if( item.m_linkage.name != "" )
+ {
+ // TODO: Save the linkage name.
+ }
+
+ // - Signature
m_of << "fn " << p << "(";
for(unsigned int i = 0; i < item.m_args.size(); i ++)
{
@@ -922,6 +1032,7 @@ namespace
m_of << params.monomorph(m_resolve, item.m_args[i].second);
}
m_of << "): " << ret_type << " {\n";
+ // - Locals
for(unsigned int i = 0; i < code->locals.size(); i ++) {
DEBUG("var" << i << " : " << code->locals[i]);
m_of << "\tlet var" << i << ": " << code->locals[i] << ";\n";
@@ -930,7 +1041,7 @@ namespace
m_of << "\tlet df" << i << " = " << code->drop_flags[i] << ";\n";
}
-
+
for(unsigned int i = 0; i < code->blocks.size(); i ++)
{
TRACE_FUNCTION_F(p << " bb" << i);
diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp
index fbf747f8..4e04ddf9 100644
--- a/src/trans/enumerate.cpp
+++ b/src/trans/enumerate.cpp
@@ -518,6 +518,11 @@ namespace {
TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (te),
(
),
+ (Function,
+ visit_type(*te.m_rettype, Mode::Shallow);
+ for(const auto& sty : te.m_arg_types)
+ visit_type(sty, Mode::Shallow);
+ ),
(Pointer,
visit_type(*te.inner, Mode::Shallow);
),
diff --git a/src/trans/main_bindings.hpp b/src/trans/main_bindings.hpp
index 46d2cdb1..b938e8bf 100644
--- a/src/trans/main_bindings.hpp
+++ b/src/trans/main_bindings.hpp
@@ -24,6 +24,13 @@ struct TransOptions
::std::vector< ::std::string> libraries;
};
+enum class CodegenOutput {
+ Object, // .o
+ StaticLibrary, // .a
+ DynamicLibrary, // .so
+ Executable, // no suffix, includes main stub (TODO: Can't that just be added earlier?)
+};
+
extern TransList Trans_Enumerate_Main(const ::HIR::Crate& crate);
// NOTE: This also sets the saveout flags
extern TransList Trans_Enumerate_Public(::HIR::Crate& crate);
diff --git a/src/trans/mangling.hpp b/src/trans/mangling.hpp
index e1b6e35e..0d13d906 100644
--- a/src/trans/mangling.hpp
+++ b/src/trans/mangling.hpp
@@ -10,7 +10,7 @@
#include <debug.hpp>
namespace HIR {
- class SimplePath;
+ struct SimplePath;
class GenericPath;
class Path;
class TypeRef;
diff --git a/src/trans/target.cpp b/src/trans/target.cpp
index 81dc8c0c..1727cdba 100644
--- a/src/trans/target.cpp
+++ b/src/trans/target.cpp
@@ -133,11 +133,11 @@ namespace
check_path_length(key_val, 3);
if( key_val.value.as_string() == "msvc" )
{
- rv.m_codegen_mode = CodegenMode::Msvc;
+ rv.m_backend_c.m_codegen_mode = CodegenMode::Msvc;
}
else if( key_val.value.as_string() == "gnu" )
{
- rv.m_codegen_mode = CodegenMode::Gnu11;
+ rv.m_backend_c.m_codegen_mode = CodegenMode::Gnu11;
}
else
{
@@ -148,7 +148,23 @@ namespace
else if( key_val.path[2] == "target" )
{
check_path_length(key_val, 3);
- rv.m_c_compiler = key_val.value.as_string();
+ rv.m_backend_c.m_c_compiler = key_val.value.as_string();
+ }
+ else if( key_val.path[2] == "compiler-opts" )
+ {
+ check_path_length(key_val, 3);
+ for(const auto& v : key_val.value.as_list())
+ {
+ rv.m_backend_c.m_compiler_opts.push_back( v.as_string() );
+ }
+ }
+ else if( key_val.path[2] == "linker-opts" )
+ {
+ check_path_length(key_val, 3);
+ for(const auto& v : key_val.value.as_list())
+ {
+ rv.m_backend_c.m_linker_opts.push_back( v.as_string() );
+ }
}
else
{
@@ -233,8 +249,56 @@ namespace
return rv;
}
+ void save_spec_to_file(const ::std::string& filename, const TargetSpec& spec)
+ {
+ // TODO: Have a round-trip unit test
+ ::std::ofstream of(filename);
+
+ struct H
+ {
+ static const char* tfstr(bool v)
+ {
+ return v ? "true" : "false";
+ }
+ static const char* c_variant_name(const CodegenMode m)
+ {
+ switch(m)
+ {
+ case CodegenMode::Gnu11: return "gnu";
+ case CodegenMode::Msvc: return "msvc";
+ }
+ return "";
+ }
+ };
+
+ of
+ << "[target]\n"
+ << "family = \"" << spec.m_family << "\"\n"
+ << "os-name = \"" << spec.m_os_name << "\"\n"
+ << "env-name = \"" << spec.m_env_name << "\"\n"
+ //<< "arch = \"" << spec.m_arch.m_name << "\"\n"
+ << "\n"
+ << "[backend.c]\n"
+ << "variant = \"" << H::c_variant_name(spec.m_backend_c.m_codegen_mode) << "\"\n"
+ << "target = \"" << spec.m_backend_c.m_c_compiler << "\"\n"
+ << "compiler-opts = [" << spec.m_backend_c.m_compiler_opts << "]\n"
+ << "linker-opts = [" << spec.m_backend_c.m_linker_opts << "]\n"
+ << "\n"
+ << "[arch]"
+ << "name = \"" << spec.m_arch.m_name << "\"\n"
+ << "pointer-bits = " << spec.m_arch.m_pointer_bits << "\n"
+ << "is-big-endian = " << H::tfstr(spec.m_arch.m_big_endian) << "\n"
+ << "has-atomic-u8 = " << H::tfstr(spec.m_arch.m_atomics.u8) << "\n"
+ << "has-atomic-u16 = " << H::tfstr(spec.m_arch.m_atomics.u16) << "\n"
+ << "has-atomic-u32 = " << H::tfstr(spec.m_arch.m_atomics.u32) << "\n"
+ << "has-atomic-u64 = " << H::tfstr(spec.m_arch.m_atomics.u64) << "\n"
+ << "has-atomic-ptr = " << H::tfstr(spec.m_arch.m_atomics.ptr) << "\n"
+ ;
+ }
TargetSpec init_from_spec_name(const ::std::string& target_name)
{
+ // Options for all the fully-GNU environments
+ #define BACKEND_C_OPTS_GNU {"-ffunction-sections", "-pthread"}, {"-Wl,--gc-sections"}
// If there's a '/' or a '\' in the filename, open it as a path, otherwise assume it's a triple.
if( target_name.find('/') != ::std::string::npos || target_name.find('\\') != ::std::string::npos )
{
@@ -243,94 +307,103 @@ namespace
else if(target_name == "i586-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", CodegenMode::Gnu11, "i586-linux-gnu",
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, "i586-linux-gnu", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
else if(target_name == "x86_64-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", CodegenMode::Gnu11, "x86_64-linux-gnu",
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, "x86_64-linux-gnu", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if(target_name == "arm-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", CodegenMode::Gnu11, "arm-elf-eabi",
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, "arm-elf-eabi", BACKEND_C_OPTS_GNU},
ARCH_ARM32
};
}
else if(target_name == "aarch64-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", CodegenMode::Gnu11, "aarch64-linux-gnu",
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, "aarch64-linux-gnu", BACKEND_C_OPTS_GNU},
ARCH_ARM64
};
}
else if(target_name == "i586-windows-gnu")
{
return TargetSpec {
- "windows", "windows", "gnu", CodegenMode::Gnu11, "mingw32",
+ "windows", "windows", "gnu", {CodegenMode::Gnu11, "mingw32", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
else if(target_name == "x86_64-windows-gnu")
{
return TargetSpec {
- "windows", "windows", "gnu", CodegenMode::Gnu11, "x86_64-w64-mingw32",
+ "windows", "windows", "gnu", {CodegenMode::Gnu11, "x86_64-w64-mingw32", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if (target_name == "x86-windows-msvc")
{
+ // TODO: Should this include the "kernel32.lib" inclusion?
return TargetSpec {
- "windows", "windows", "msvc", CodegenMode::Msvc, "x86",
+ "windows", "windows", "msvc", {CodegenMode::Msvc, "x86", {}, {}},
ARCH_X86
};
}
else if (target_name == "x86_64-windows-msvc")
{
return TargetSpec {
- "windows", "windows", "msvc", CodegenMode::Msvc, "amd64",
+ "windows", "windows", "msvc", {CodegenMode::Msvc, "amd64", {}, {}},
ARCH_X86_64
};
}
else if(target_name == "x86_64-unknown-netbsd")
{
return TargetSpec {
- "unix", "netbsd", "gnu", CodegenMode::Gnu11, "x86_64-unknown-netbsd",
+ "unix", "netbsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-netbsd", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if(target_name == "i686-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", CodegenMode::Gnu11, "i686-unknown-openbsd",
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "i686-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
else if(target_name == "x86_64-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", CodegenMode::Gnu11, "x86_64-unknown-openbsd",
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if(target_name == "arm-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", CodegenMode::Gnu11, "arm-unknown-openbsd",
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "arm-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_ARM32
};
}
else if(target_name == "aarch64-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", CodegenMode::Gnu11, "aarch64-unknown-openbsd",
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "aarch64-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_ARM64
};
}
+ else if(target_name == "x86_64-apple-macosx")
+ {
+ // NOTE: OSX uses clang and lld, which don't fully support the defaults used for GNU targets
+ return TargetSpec {
+ "unix", "macos", "gnu", {CodegenMode::Gnu11, "x86_64-apple-darwin", {}, {}},
+ ARCH_X86_64
+ };
+ }
else
{
::std::cerr << "Unknown target name '" << target_name << "'" << ::std::endl;
@@ -344,6 +417,10 @@ const TargetSpec& Target_GetCurSpec()
{
return g_target;
}
+void Target_ExportCurSpec(const ::std::string& filename)
+{
+ save_spec_to_file(filename, g_target);
+}
void Target_SetCfg(const ::std::string& target_name)
{
g_target = init_from_spec_name(target_name);
@@ -445,7 +522,7 @@ namespace {
{
case ::HIR::Struct::Repr::Packed:
packed = true;
- TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen help
+ TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen to know to pack the structure
break;
case ::HIR::Struct::Repr::C:
// No sorting, no packing
@@ -526,8 +603,6 @@ const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve&
return ires.first->second.get();
}
-// TODO: Include NonZero and other repr optimisations here
-
bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align)
{
TRACE_FUNCTION_FR(ty, "size=" << out_size << ", align=" << out_align);
@@ -684,8 +759,7 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve,
return true;
),
(Closure,
- // TODO.
- DEBUG("TODO Closure - " << ty);
+ BUG(sp, "Encountered closure type at trans stage - " << ty);
)
)
return false;
@@ -769,8 +843,9 @@ namespace {
switch(str.m_repr)
{
case ::HIR::Struct::Repr::Packed:
+ // packed, not sorted
packed = true;
- TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen help
+ // NOTE: codegen_c checks m_repr for packing too
break;
case ::HIR::Struct::Repr::C:
// No sorting, no packing
@@ -792,10 +867,6 @@ namespace {
DEBUG("Can't get size/align of " << t);
return nullptr;
}
- if( size == SIZE_MAX )
- {
- TODO(sp, "Unsized type in struct - " << t);
- }
ents.push_back(Ent { idx++, size, align });
fields.push_back(TypeRepr::Field { 0, t.clone() });
}
@@ -808,9 +879,12 @@ namespace {
if( allow_sort )
{
- // TODO: Sort by alignment then size (largest first)
- // - Requires codegen to use this information
+ // Sort by alignment then size (largest first)
// - NOTE: ?Sized fields (which includes unsized fields) MUST be at the end, even after monomorph
+ // - This means that this code needs to know if a field was ?Sized
+ // TODO: Determine if a field was from a ?Sized generic (so should be fixed as last)
+ //auto cmpfn_lt = [](const Ent& a, const Ent& b){ return a.align == b.align ? a.size < b.size : a.align < b.size; };
+ //::std::sort(ents.begin(), ents.end(), cmpfn_lt);
}
TypeRepr rv;
@@ -831,7 +905,7 @@ namespace {
fields[e.field].offset = cur_ofs;
if( e.size == SIZE_MAX )
{
- // TODO: Ensure that this is the last item
+ // Ensure that this is the last item
ASSERT_BUG(sp, &e == &ents.back(), "Unsized item isn't the last item in " << ty);
cur_ofs = SIZE_MAX;
}
@@ -876,6 +950,13 @@ namespace {
return true;
}
}
+ // Handle the NonZero lang item (Note: Checks just the simplepath part)
+ if( te.path.m_data.as_Generic().m_path == resolve.m_crate.get_lang_item_path(sp, "non_zero") )
+ {
+ out_path.sub_fields.push_back(0);
+ out_path.size = r->size;
+ return true;
+ }
}
} break;
TU_ARM(ty.m_data, Borrow, _te) { (void)_te;
@@ -919,6 +1000,7 @@ namespace {
{
nz_path.index = 1;
::std::reverse(nz_path.sub_fields.begin(), nz_path.sub_fields.end());
+ DEBUG("nz_path = " << nz_path.sub_fields);
size_t max_size = 0;
size_t max_align = 0;
for(auto& t : mono_types)
@@ -969,7 +1051,7 @@ namespace {
max_size ++;
}
size_t tag_size = 0;
- // TODO: repr(C) enums
+ // TODO: repr(C) enums - they have different rules
if( mono_types.size() == 0 ) {
// Unreachable
}
@@ -1014,8 +1096,6 @@ namespace {
{
ASSERT_BUG(sp, max_size == 0, "Zero alignment, but non-zero size");
}
-
- // TODO: Variants.
}
} break;
TU_ARM(enm.m_data, Value, e) {
diff --git a/src/trans/target.hpp b/src/trans/target.hpp
index 81205831..b1ed9456 100644
--- a/src/trans/target.hpp
+++ b/src/trans/target.hpp
@@ -31,14 +31,20 @@ struct TargetArch
bool ptr;
} m_atomics;
};
+struct BackendOptsC
+{
+ CodegenMode m_codegen_mode;
+ ::std::string m_c_compiler; // MSVC arch / GNU triplet
+ ::std::vector< ::std::string> m_compiler_opts;
+ ::std::vector< ::std::string> m_linker_opts;
+};
struct TargetSpec
{
::std::string m_family;
::std::string m_os_name;
::std::string m_env_name;
- CodegenMode m_codegen_mode;
- ::std::string m_c_compiler; // MSVC arch / GNU triplet
+ BackendOptsC m_backend_c;
TargetArch m_arch;
};
@@ -96,6 +102,8 @@ struct TypeRepr
extern const TargetSpec& Target_GetCurSpec();
extern void Target_SetCfg(const ::std::string& target_name);
+extern void Target_ExportCurSpec(const ::std::string& filename);
+
extern bool Target_GetSizeOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size);
extern bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_align);
extern bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align);
diff --git a/test_smiri.sh b/test_smiri.sh
new file mode 100755
index 00000000..a275420a
--- /dev/null
+++ b/test_smiri.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+set -e
+cd $(dirname $0)
+make -f minicargo.mk MMIR=1 LIBS
+make -C tools/standalone_miri
+echo "--- mrustc -o output-mmir/hello"
+./bin/mrustc rustc-1.19.0-src/src/test/run-pass/hello.rs -O -C codegen-type=monomir -o output-mmir/hello -L output-mmir/ > output-mmir/hello_dbg.txt
+echo "--- standalone_miri output-mmir/hello.mir"
+time ./tools/bin/standalone_miri output-mmir/hello.mir --logfile smiri_hello.log
diff --git a/tools/common/debug.cpp b/tools/common/debug.cpp
index a3fb9956..94d8ed99 100644
--- a/tools/common/debug.cpp
+++ b/tools/common/debug.cpp
@@ -34,6 +34,14 @@ void Debug_DisablePhase(const char* phase_name)
{
gmDisabledDebug.insert( ::std::string(phase_name) );
}
+void Debug_EnablePhase(const char* phase_name)
+{
+ auto it = gmDisabledDebug.find(phase_name);
+ if( it != gmDisabledDebug.end() )
+ {
+ gmDisabledDebug.erase(it);
+ }
+}
void Debug_Print(::std::function<void(::std::ostream& os)> cb)
{
if( !Debug_IsEnabled() )
diff --git a/tools/common/debug.h b/tools/common/debug.h
index ace00876..86c88de9 100644
--- a/tools/common/debug.h
+++ b/tools/common/debug.h
@@ -7,6 +7,7 @@
typedef ::std::function<void(::std::ostream& os)> dbg_cb_t;
extern void Debug_SetPhase(const char* phase_name);
extern void Debug_DisablePhase(const char* phase_name);
+extern void Debug_EnablePhase(const char* phase_name);
extern bool Debug_IsEnabled();
extern void Debug_EnterScope(const char* name, dbg_cb_t );
extern void Debug_LeaveScope(const char* name, dbg_cb_t );
diff --git a/tools/common/target_detect.h b/tools/common/target_detect.h
new file mode 100644
index 00000000..995ab6a4
--- /dev/null
+++ b/tools/common/target_detect.h
@@ -0,0 +1,66 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * common/target_detect.h
+ * - Auto-magical host target detection
+ */
+#pragma once
+
+// - Windows (MSVC)
+#ifdef _MSC_VER
+# if defined(_WIN64)
+# define DEFAULT_TARGET_NAME "x86_64-windows-msvc"
+# else
+# define DEFAULT_TARGET_NAME "x86-windows-msvc"
+# endif
+// - Linux
+#elif defined(__linux__)
+# if defined(__amd64__)
+# define DEFAULT_TARGET_NAME "x86_64-linux-gnu"
+# elif defined(__aarch64__)
+# define DEFAULT_TARGET_NAME "aarch64-linux-gnu"
+# elif defined(__arm__)
+# define DEFAULT_TARGET_NAME "arm-linux-gnu"
+# elif defined(__i386__)
+# define DEFAULT_TARGET_NAME "i586-linux-gnu"
+# else
+# warning "Unable to detect a suitable default target (linux-gnu)"
+# endif
+// - MinGW
+#elif defined(__MINGW32__)
+# if defined(_WIN64)
+# define DEFAULT_TARGET_NAME "x86_64-windows-gnu"
+# else
+# define DEFAULT_TARGET_NAME "i586-windows-gnu"
+# endif
+// - NetBSD
+#elif defined(__NetBSD__)
+# if defined(__amd64__)
+# define DEFAULT_TARGET_NAME "x86_64-unknown-netbsd"
+# else
+# warning "Unable to detect a suitable default target (NetBSD)"
+# endif
+// - OpenBSD
+#elif defined(__OpenBSD__)
+# if defined(__amd64__)
+# define DEFAULT_TARGET_NAME "x86_64-unknown-openbsd"
+# elif defined(__aarch64__)
+# define DEFAULT_TARGET_NAME "aarch64-unknown-openbsd"
+# elif defined(__arm__)
+# define DEFAULT_TARGET_NAME "arm-unknown-openbsd"
+# elif defined(__i386__)
+# define DEFAULT_TARGET_NAME "i686-unknown-openbsd"
+# else
+# warning "Unable to detect a suitable default target (OpenBSD)"
+# endif
+// - Apple devices
+#elif defined(__APPLE__)
+# define DEFAULT_TARGET_NAME "x86_64-apple-macosx"
+// - Unknown
+#else
+# warning "Unable to detect a suitable default target"
+#endif
+#ifndef DEFAULT_TARGET_NAME
+# define DEFAULT_TARGET_NAME ""
+#endif
diff --git a/tools/common/toml.cpp b/tools/common/toml.cpp
index 9fad0ec4..75a93810 100644
--- a/tools/common/toml.cpp
+++ b/tools/common/toml.cpp
@@ -170,9 +170,11 @@ TomlKeyValue TomlFile::get_next_value()
throw ::std::runtime_error(::format("Unexpected token after key - ", t));
t = Token::lex_from(m_if);
+ // --- Value ---
TomlKeyValue rv;
switch(t.m_type)
{
+ // String: Return the string value
case Token::Type::String:
rv.path = m_current_block;
rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end());
@@ -180,6 +182,7 @@ TomlKeyValue TomlFile::get_next_value()
rv.value = TomlValue { t.m_data };
break;
+ // Array: Parse the entire list and return as Type::List
case Token::Type::SquareOpen:
rv.path = m_current_block;
rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end());
@@ -193,7 +196,8 @@ TomlKeyValue TomlFile::get_next_value()
if( t.m_type == Token::Type::SquareClose )
break;
- // TODO: Recurse parse a value
+ // TODO: Recursively parse a value
+ // TODO: OR, support other value types
switch(t.m_type)
{
case Token::Type::String:
diff --git a/tools/minicargo/Makefile b/tools/minicargo/Makefile
index 01010fb5..363ef4b9 100644
--- a/tools/minicargo/Makefile
+++ b/tools/minicargo/Makefile
@@ -38,7 +38,7 @@ $(OBJDIR)%.o: %.cpp
@echo [CXX] $<
$V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep
-../bin/common_lib.a:
+../bin/common_lib.a: $(wildcard ../common/*.* ../common/Makefile)
make -C ../common
-include $(OBJS:%.o=%.o.dep)
diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp
index c7c07256..42e19552 100644
--- a/tools/minicargo/build.cpp
+++ b/tools/minicargo/build.cpp
@@ -42,22 +42,17 @@ extern int _putenv_s(const char*, const char*);
# include <sys/wait.h>
# include <fcntl.h>
#endif
+#ifdef __APPLE__
+# include <mach-o/dyld.h>
+#endif
#ifdef _WIN32
# define EXESUF ".exe"
-# ifdef _MSC_VER
-# define HOST_TARGET "x86_64-windows-msvc"
-# elif defined(__MINGW32__)
-# define HOST_TARGET "x86_64-windows-gnu"
-# else
-# endif
-#elif defined(__NetBSD__)
-# define EXESUF ""
-# define HOST_TARGET "x86_64-unknown-netbsd"
#else
# define EXESUF ""
-# define HOST_TARGET "x86_64-unknown-linux-gnu"
#endif
+#include <target_detect.h> // tools/common/target_detect.h
+#define HOST_TARGET DEFAULT_TARGET_NAME
/// Class abstracting access to the compiler
class Builder
@@ -549,12 +544,32 @@ Builder::Builder(BuildOptions opts):
#ifdef __MINGW32__
m_compiler_path = (minicargo_path / "..\\..\\bin\\mrustc.exe").normalise();
#else
+ // MSVC, minicargo and mrustc are in the same dir
m_compiler_path = minicargo_path / "mrustc.exe";
#endif
#else
char buf[1024];
- size_t s = readlink("/proc/self/exe", buf, sizeof(buf)-1);
- buf[s] = 0;
+# ifdef __linux__
+ ssize_t s = readlink("/proc/self/exe", buf, sizeof(buf)-1);
+ if(s >= 0)
+ {
+ buf[s] = 0;
+ }
+ else
+#elif defined(__APPLE__)
+ uint32_t s = sizeof(buf);
+ if( _NSGetExecutablePath(buf, &s) == 0 )
+ {
+ // Buffer populated
+ }
+ else
+ // TODO: Buffer too small
+#else
+# warning "Can't runtime determine path to minicargo"
+#endif
+ {
+ strcpy(buf, "tools/bin/minicargo");
+ }
::helpers::path minicargo_path { buf };
minicargo_path.pop_component();
@@ -803,7 +818,7 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget&
auto out_file = output_dir_abs / "build_" + manifest.name().c_str() + ".txt";
auto out_dir = output_dir_abs / "build_" + manifest.name().c_str();
-
+
bool run_build_script = false;
// TODO: Handle a pre-existing script containing `cargo:rerun-if-changed`
auto script_exe = this->build_build_script(manifest, is_for_host, &run_build_script);
@@ -813,7 +828,8 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget&
return ::helpers::path();
}
- if( run_build_script )
+ // If the script changed, OR the output file doesn't exist
+ if( run_build_script || Timestamp::for_file(out_file) == Timestamp::infinite_past() )
{
auto script_exe_abs = script_exe.to_absolute();
@@ -1007,8 +1023,8 @@ bool Builder::spawn_process(const char* exe_name, const StringList& args, const
if( posix_spawn(&pid, exe_name, &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.get_vec().data()) != 0 )
{
- perror("posix_spawn");
- DEBUG("Unable to spawn compiler");
+ ::std::cerr << "Unable to run process '" << exe_name << "' - " << strerror(errno) << ::std::endl;
+ DEBUG("Unable to spawn executable");
posix_spawn_file_actions_destroy(&fa);
return false;
}
diff --git a/tools/minicargo/main.cpp b/tools/minicargo/main.cpp
index 50e08619..b185881b 100644
--- a/tools/minicargo/main.cpp
+++ b/tools/minicargo/main.cpp
@@ -54,11 +54,29 @@ int main(int argc, const char* argv[])
return 1;
}
- Debug_DisablePhase("Load Repository");
- Debug_DisablePhase("Load Root");
- Debug_DisablePhase("Load Dependencies");
- Debug_DisablePhase("Enumerate Build");
- //Debug_DisablePhase("Run Build");
+ {
+ Debug_DisablePhase("Load Repository");
+ Debug_DisablePhase("Load Root");
+ Debug_DisablePhase("Load Dependencies");
+ Debug_DisablePhase("Enumerate Build");
+ Debug_DisablePhase("Run Build");
+
+ if( const char* e = getenv("MINICARGO_DEBUG") )
+ {
+ while( *e )
+ {
+ const char* colon = ::std::strchr(e, ':');
+ size_t len = colon ? colon - e : ::std::strlen(e);
+
+ Debug_EnablePhase(::std::string(e, len).c_str());
+
+ if( colon )
+ e = colon + 1;
+ else
+ e = e + len;
+ }
+ }
+ }
try
{
diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp
index 6e2bf451..687c3e2a 100644
--- a/tools/minicargo/manifest.cpp
+++ b/tools/minicargo/manifest.cpp
@@ -9,7 +9,7 @@
#include <cctype> // toupper
#include "repository.h"
-
+// TODO: Extract this from the target at runtime
#ifdef _WIN32
# define TARGET_NAME "i586-windows-msvc"
# define CFG_UNIX false
diff --git a/tools/standalone_miri/Makefile b/tools/standalone_miri/Makefile
new file mode 100644
index 00000000..f4dc0d0d
--- /dev/null
+++ b/tools/standalone_miri/Makefile
@@ -0,0 +1,44 @@
+#
+# Standalone MIR Interpreter
+#
+ifeq ($(OS),Windows_NT)
+ EXESUF ?= .exe
+endif
+EXESUF ?=
+
+V ?= @
+
+OBJDIR := .obj/
+
+BIN := ../bin/standalone_miri$(EXESUF)
+OBJS := main.o debug.o mir.o lex.o value.o module_tree.o hir_sim.o miri.o
+
+LINKFLAGS := -g -lpthread
+CXXFLAGS := -Wall -std=c++14 -g -O2
+CXXFLAGS += -I ../common -I ../../src/include -I .
+CXXFLAGS += -Wno-misleading-indentation # Gets REALLY confused by the TU_ARM macro
+
+OBJS := $(OBJS:%=$(OBJDIR)%)
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+ rm $(BIN) $(OBJS)
+
+$(BIN): $(OBJS) ../bin/common_lib.a
+ @mkdir -p $(dir $@)
+ @echo [CXX] -o $@
+ $V$(CXX) -o $@ $(OBJS) ../bin/common_lib.a $(LINKFLAGS)
+
+$(OBJDIR)%.o: %.cpp
+ @mkdir -p $(dir $@)
+ @echo [CXX] $<
+ $V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep
+
+../bin/common_lib.a:
+ make -C ../common
+
+-include $(OBJS:%.o=%.o.dep)
+
diff --git a/tools/standalone_miri/debug.cpp b/tools/standalone_miri/debug.cpp
index 415bc5d5..c49df960 100644
--- a/tools/standalone_miri/debug.cpp
+++ b/tools/standalone_miri/debug.cpp
@@ -1,6 +1,15 @@
+/*
+ * mrustc Standalone MIRI
+ * - by John Hodge (Mutabah)
+ *
+ * debug.cpp
+ * - Interpreter debug logging
+ */
#include "debug.hpp"
+#include <fstream>
unsigned DebugSink::s_indent = 0;
+::std::unique_ptr<std::ofstream> DebugSink::s_out_file;
DebugSink::DebugSink(::std::ostream& inner):
m_inner(inner)
@@ -9,6 +18,11 @@ DebugSink::DebugSink(::std::ostream& inner):
DebugSink::~DebugSink()
{
m_inner << "\n";
+ m_inner.flush();
+}
+void DebugSink::set_output_file(const ::std::string& s)
+{
+ s_out_file.reset(new ::std::ofstream(s));
}
bool DebugSink::enabled(const char* fcn_name)
{
@@ -16,33 +30,34 @@ bool DebugSink::enabled(const char* fcn_name)
}
DebugSink DebugSink::get(const char* fcn_name, const char* file, unsigned line, DebugLevel lvl)
{
+ auto& sink = s_out_file ? *s_out_file : ::std::cout;
for(size_t i = s_indent; i--;)
- ::std::cout << " ";
+ sink << " ";
switch(lvl)
{
case DebugLevel::Trace:
- ::std::cout << "Trace: " << file << ":" << line << ": ";
+ sink << "Trace: " << file << ":" << line << ": ";
break;
case DebugLevel::Debug:
- ::std::cout << "DEBUG: " << fcn_name << ": ";
+ sink << "DEBUG: " << fcn_name << ": ";
break;
case DebugLevel::Notice:
- ::std::cout << "NOTE: ";
+ sink << "NOTE: ";
break;
case DebugLevel::Warn:
- ::std::cout << "WARN: ";
+ sink << "WARN: ";
break;
case DebugLevel::Error:
- ::std::cout << "ERROR: ";
+ sink << "ERROR: ";
break;
case DebugLevel::Fatal:
- ::std::cout << "FATAL: ";
+ sink << "FATAL: ";
break;
case DebugLevel::Bug:
- ::std::cout << "BUG: " << file << ":" << line << ": ";
+ sink << "BUG: " << file << ":" << line << ": ";
break;
}
- return DebugSink(::std::cout);
+ return DebugSink(sink);
}
void DebugSink::inc_indent()
{
@@ -51,4 +66,4 @@ void DebugSink::inc_indent()
void DebugSink::dec_indent()
{
s_indent --;
-} \ No newline at end of file
+}
diff --git a/tools/standalone_miri/debug.hpp b/tools/standalone_miri/debug.hpp
index 5afad96e..b3b0d76f 100644
--- a/tools/standalone_miri/debug.hpp
+++ b/tools/standalone_miri/debug.hpp
@@ -1,10 +1,15 @@
-//
-//
-//
+/*
+ * mrustc Standalone MIRI
+ * - by John Hodge (Mutabah)
+ *
+ * debug.hpp
+ * - Interpreter debug logging
+ */
#pragma once
#include <iostream>
#include <functional>
+#include <memory>
enum class DebugLevel {
Trace,
@@ -19,6 +24,7 @@ enum class DebugLevel {
class DebugSink
{
static unsigned s_indent;
+ static ::std::unique_ptr<std::ofstream> s_out_file;
::std::ostream& m_inner;
DebugSink(::std::ostream& inner);
public:
@@ -27,6 +33,7 @@ public:
template<typename T>
::std::ostream& operator<<(const T& v) { return m_inner << v; }
+ static void set_output_file(const ::std::string& s);
static bool enabled(const char* fcn_name);
static DebugSink get(const char* fcn_name, const char* file, unsigned line, DebugLevel lvl);
// TODO: Add a way to insert an annotation before/after an abort/warning/... that indicates what input location caused it.
@@ -75,14 +82,14 @@ FunctionTrace<T,U> FunctionTrace_d(const char* fname, const char* file, unsigned
struct DebugExceptionTodo:
public ::std::exception
{
- const char* what() const {
+ const char* what() const noexcept override {
return "TODO hit";
}
};
struct DebugExceptionError:
public ::std::exception
{
- const char* what() const {
+ const char* what() const noexcept override {
return "error";
}
};
@@ -90,6 +97,7 @@ struct DebugExceptionError:
#define TRACE_FUNCTION_R(entry, exit) auto ftg##__LINE__ = FunctionTrace_d(__FUNCTION__,__FILE__,__LINE__,[&](DebugSink& FunctionTrace_ss){FunctionTrace_ss << entry;}, [&](DebugSink& FunctionTrace_ss) {FunctionTrace_ss << exit;} )
#define LOG_TRACE(strm) do { if(DebugSink::enabled(__FUNCTION__)) DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Trace) << strm; } while(0)
#define LOG_DEBUG(strm) do { if(DebugSink::enabled(__FUNCTION__)) DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Debug) << strm; } while(0)
+#define LOG_NOTICE(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Notice) << strm; } while(0)
#define LOG_ERROR(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Error) << strm; throw DebugExceptionError{}; } while(0)
#define LOG_FATAL(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Fatal) << strm; exit(1); } while(0)
#define LOG_TODO(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "TODO: " << strm; throw DebugExceptionTodo{}; } while(0)
diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp
index 604f65a4..88739730 100644
--- a/tools/standalone_miri/hir_sim.cpp
+++ b/tools/standalone_miri/hir_sim.cpp
@@ -1,7 +1,12 @@
-//
-//
-//
+/*
+ * mrustc Standalone MIRI
+ * - by John Hodge (Mutabah)
+ *
+ * value.cpp
+ * - Copy of the various HIR types from the compiler
+ */
#include <iostream>
+#include <algorithm>
#include "hir_sim.hpp"
#include "module_tree.hpp"
@@ -13,13 +18,65 @@
size_t HIR::TypeRef::get_size(size_t ofs) const
{
- if( this->wrappers.size() <= ofs )
+ if( const auto* w = this->get_wrapper(ofs) )
+ {
+ switch(w->type)
+ {
+ case TypeWrapper::Ty::Array:
+ return this->get_size(1) * w->size;
+ case TypeWrapper::Ty::Borrow:
+ case TypeWrapper::Ty::Pointer:
+ if( const auto* next_w = this->get_wrapper(ofs+1) )
+ {
+ if( next_w->type == TypeWrapper::Ty::Slice )
+ {
+ return POINTER_SIZE*2;
+ }
+ else
+ {
+ return POINTER_SIZE;
+ }
+ }
+ else
+ {
+ // Need to look up the metadata type for the actual type
+ if( this->inner_type == RawType::Composite )
+ {
+ if( this->composite_type->dst_meta == RawType::Unreachable )
+ {
+ return POINTER_SIZE;
+ }
+ // Special case: extern types (which appear when a type is only ever used by pointer)
+ if( this->composite_type->dst_meta == RawType::Unit )
+ {
+ return POINTER_SIZE;
+ }
+
+ // TODO: Ideally, this inner type wouldn't be unsized itself... but checking that would be interesting.
+ return POINTER_SIZE + this->composite_type->dst_meta.get_size();
+ }
+ else if( this->inner_type == RawType::Str )
+ return POINTER_SIZE*2;
+ else if( this->inner_type == RawType::TraitObject )
+ return POINTER_SIZE*2;
+ else
+ {
+ return POINTER_SIZE;
+ }
+ }
+ case TypeWrapper::Ty::Slice:
+ LOG_BUG("Getting size of a slice - " << *this);
+ }
+ throw "";
+ }
+ else
{
switch(this->inner_type)
{
case RawType::Unit:
return 0;
case RawType::Composite:
+ // NOTE: Don't care if the type has metadata
return this->composite_type->size;
case RawType::Unreachable:
LOG_BUG("Attempting to get size of an unreachable type, " << *this);
@@ -53,92 +110,88 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
}
throw "";
}
-
- switch(this->wrappers[ofs].type)
- {
- case TypeWrapper::Ty::Array:
- return this->get_size(1) * this->wrappers[ofs].size;
- case TypeWrapper::Ty::Borrow:
- case TypeWrapper::Ty::Pointer:
- if( this->wrappers.size() == ofs+1 )
- {
- // Need to look up the metadata type for the actual type
- if( this->inner_type == RawType::Composite )
- {
- if( this->composite_type->dst_meta == RawType::Unreachable )
- {
- return POINTER_SIZE;
- }
- // Special case: extern types (which appear when a type is only ever used by pointer)
- if( this->composite_type->dst_meta == RawType::Unit )
- {
- return POINTER_SIZE;
- }
-
- // TODO: Ideally, this inner type wouldn't be unsized itself... but checking that would be interesting.
- return POINTER_SIZE + this->composite_type->dst_meta.get_size();
- }
- else if( this->inner_type == RawType::Str )
- return POINTER_SIZE*2;
- else if( this->inner_type == RawType::TraitObject )
- return POINTER_SIZE*2;
- else
- {
- return POINTER_SIZE;
- }
- }
- else if( this->wrappers[ofs+1].type == TypeWrapper::Ty::Slice )
- {
- return POINTER_SIZE*2;
- }
- else
- {
- return POINTER_SIZE;
- }
- case TypeWrapper::Ty::Slice:
- LOG_BUG("Getting size of a slice - " << *this);
- }
- throw "";
}
-bool HIR::TypeRef::has_slice_meta() const
+bool HIR::TypeRef::has_slice_meta(size_t& out_inner_size) const
{
- if( this->wrappers.size() == 0 )
+ if( const auto* w = this->get_wrapper() )
+ {
+ out_inner_size = this->get_size(1);
+ return (w->type == TypeWrapper::Ty::Slice);
+ }
+ else
{
if(this->inner_type == RawType::Composite)
{
- // TODO: Handle metadata better
+ // TODO: This type could be wrapping a slice, needs to return the inner type size.
+ // - Also need to know which field is the unsized one
return false;
}
else
{
+ out_inner_size = 1;
return (this->inner_type == RawType::Str);
}
}
- else
- {
- return (this->wrappers[0].type == TypeWrapper::Ty::Slice);
- }
}
HIR::TypeRef HIR::TypeRef::get_inner() const
{
if( this->wrappers.empty() )
{
- throw "ERROR";
+ LOG_ERROR("Getting inner of a non-wrapped type - " << *this);
+ }
+ else
+ {
+ auto ity = *this;
+ ity.wrappers.erase(ity.wrappers.begin());
+ return ity;
}
- auto ity = *this;
- ity.wrappers.erase(ity.wrappers.begin());
- return ity;
}
-HIR::TypeRef HIR::TypeRef::wrap(TypeWrapper::Ty ty, size_t size) const
+HIR::TypeRef HIR::TypeRef::wrap(TypeWrapper::Ty ty, size_t size)&&
{
- auto rv = *this;
+ auto rv = ::std::move(*this);
rv.wrappers.insert(rv.wrappers.begin(), { ty, size });
return rv;
}
-const HIR::TypeRef* HIR::TypeRef::get_usized_type(size_t& running_inner_size) const
+bool HIR::TypeRef::has_pointer() const
{
- if( this->wrappers.empty() )
+ // If ALL of the (potentially non) wrappers are Array, look deeper
+ // - Don't need to worry about unsized types here
+ if( ::std::all_of(this->wrappers.begin(), this->wrappers.end(), [](const auto& x){ return x.type == TypeWrapper::Ty::Array; }) )
+ {
+ // TODO: Function pointers should be _pointers_
+ if( this->inner_type == RawType::Function )
+ {
+ return true;
+ }
+ // Check the inner type
+ if( this->inner_type == RawType::Composite )
+ {
+ // Still not sure, check the inner for any pointers.
+ for(const auto& fld : this->composite_type->fields)
+ {
+ if( fld.second.has_pointer() )
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+}
+const HIR::TypeRef* HIR::TypeRef::get_unsized_type(size_t& running_inner_size) const
+{
+ if( const auto* w = this->get_wrapper() )
+ {
+ if( w->type == TypeWrapper::Ty::Slice )
+ {
+ return this;
+ }
+ else
+ {
+ return nullptr;
+ }
+ }
+ else
{
switch(this->inner_type)
{
@@ -149,7 +202,7 @@ const HIR::TypeRef* HIR::TypeRef::get_usized_type(size_t& running_inner_size) co
return nullptr;
running_inner_size = this->composite_type->fields.back().first;
size_t tmp;
- return this->composite_type->fields.back().second.get_usized_type(tmp);
+ return this->composite_type->fields.back().second.get_unsized_type(tmp);
case RawType::TraitObject:
case RawType::Str:
return this;
@@ -157,47 +210,60 @@ const HIR::TypeRef* HIR::TypeRef::get_usized_type(size_t& running_inner_size) co
return nullptr;
}
}
- else if( this->wrappers[0].type == TypeWrapper::Ty::Slice )
+}
+HIR::TypeRef HIR::TypeRef::get_meta_type() const
+{
+ if( const auto* w = this->get_wrapper() )
{
- return this;
+ if( w->type == TypeWrapper::Ty::Slice )
+ {
+ return TypeRef(RawType::USize);
+ }
+ else
+ {
+ return TypeRef(RawType::Unreachable);
+ }
}
else
{
- return nullptr;
- }
-}
-const HIR::TypeRef* HIR::TypeRef::get_meta_type() const
-{
- static ::HIR::TypeRef static_usize = ::HIR::TypeRef(RawType::USize);
- if( this->wrappers.empty() )
- {
switch(this->inner_type)
{
case RawType::Composite:
if( this->composite_type->dst_meta == RawType::Unreachable )
- return nullptr;
- return &this->composite_type->dst_meta;
+ return TypeRef(RawType::Unreachable);
+ return this->composite_type->dst_meta;
case RawType::TraitObject:
- LOG_TODO("get_meta_type on TraitObject - " << *this);
+ return ::HIR::TypeRef(this->composite_type).wrap( TypeWrapper::Ty::Pointer, static_cast<size_t>(BorrowType::Shared) );
case RawType::Str:
- return &static_usize;
+ return TypeRef(RawType::USize);
default:
- return nullptr;
+ return TypeRef(RawType::Unreachable);
}
}
- else if( this->wrappers[0].type == TypeWrapper::Ty::Slice )
- {
- return &static_usize;
- }
- else
- {
- return nullptr;
- }
}
HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const
{
- if( this->wrappers.empty() )
+ if( const auto* w = this->get_wrapper() )
+ {
+ if( w->type == TypeWrapper::Ty::Slice )
+ {
+ // TODO
+ throw "TODO";
+ }
+ else if( w->type == TypeWrapper::Ty::Array )
+ {
+ LOG_ASSERT(idx < w->size, "Getting field on array with OOB index - " << idx << " >= " << w->size << " - " << *this);
+ auto ity = this->get_inner();
+ ofs = ity.get_size() * idx;
+ return ity;
+ }
+ else
+ {
+ throw "ERROR";
+ }
+ }
+ else
{
if( this->inner_type == RawType::Composite )
{
@@ -211,21 +277,6 @@ HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const
throw "ERROR";
}
}
- else if( this->wrappers.front().type == TypeWrapper::Ty::Slice )
- {
- // TODO
- throw "TODO";
- }
- else if( this->wrappers.front().type == TypeWrapper::Ty::Array )
- {
- auto ity = this->get_inner();
- ofs = ity.get_size() * idx;
- return ity;
- }
- else
- {
- throw "ERROR";
- }
}
size_t HIR::TypeRef::get_field_ofs(size_t base_idx, const ::std::vector<size_t>& other_idx, TypeRef& ty) const
{
@@ -305,7 +356,11 @@ namespace HIR {
os << "function_?";
break;
case RawType::TraitObject:
- os << "traitobject_?";
+ os << "dyn ";
+ if( x.composite_type )
+ os << x.composite_type->my_path;
+ else
+ os << "?";
break;
case RawType::Bool: os << "bool"; break;
case RawType::Char: os << "char"; break;
@@ -385,4 +440,4 @@ namespace HIR {
}
return os;
}
-} \ No newline at end of file
+}
diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp
index 7154de13..7730ac48 100644
--- a/tools/standalone_miri/hir_sim.hpp
+++ b/tools/standalone_miri/hir_sim.hpp
@@ -23,7 +23,7 @@ struct DataType;
enum class RawType
{
Unreachable,
- Function,
+ Function, // TODO: Needs a way of indicating the signature?
Unit,
Bool,
@@ -39,7 +39,7 @@ enum class RawType
Char, Str,
Composite, // Struct, Enum, Union, tuple, ...
- TraitObject, // Data pointer is `*const ()`, metadata type stored in `composite_type`
+ TraitObject, // Data pointer is `*const ()`, vtable type stored in `composite_type`
};
struct TypeWrapper
{
@@ -118,12 +118,41 @@ namespace HIR {
}
size_t get_size(size_t ofs=0) const;
- bool has_slice_meta() const; // The attached metadata is a count
- const TypeRef* get_usized_type(size_t& running_inner_size) const;
- const TypeRef* get_meta_type() const;
+
+ // Returns true if this (unsized) type is a wrapper around a slice
+ // - Fills `out_inner_size` with the size of the slice element
+ bool has_slice_meta(size_t& out_inner_size) const; // The attached metadata is a count of elements
+ // Returns the base unsized type for this type (returning nullptr if there's no unsized field)
+ // - Fills `running_inner_size` with the offset to the unsized field
+ const TypeRef* get_unsized_type(size_t& running_inner_size) const;
+ // Returns the type of associated metadata for this (unsized) type (or `!` if not unsized)
+ TypeRef get_meta_type() const;
+ // Get the inner type (one level of wrapping removed)
TypeRef get_inner() const;
- TypeRef wrap(TypeWrapper::Ty ty, size_t size) const;
+
+ // Add a wrapper over this type (moving)
+ TypeRef wrap(TypeWrapper::Ty ty, size_t size)&&;
+ // Add a wrapper over this type (copying)
+ TypeRef wrapped(TypeWrapper::Ty ty, size_t size) const {
+ return TypeRef(*this).wrap(ty, size);
+ }
+ // Get the wrapper at the provided offset (0 = outermost)
+ const TypeWrapper* get_wrapper(size_t ofs=0) const {
+ //assert(ofs <= this->wrappers.size());
+ if( ofs < this->wrappers.size() ) {
+ return &this->wrappers[ofs];
+ }
+ else {
+ return nullptr;
+ }
+ }
+
+ // Returns true if the type contains any pointers
+ bool has_pointer() const;
+ // Get the type and offset of the specified field index
TypeRef get_field(size_t idx, size_t& ofs) const;
+ // Get the offset and type of a field (recursing using `other_idx`)
+ size_t get_field_ofs(size_t idx, const ::std::vector<size_t>& other_idx, TypeRef& ty) const;
bool operator==(const RawType& x) const {
if( this->wrappers.size() != 0 )
@@ -149,8 +178,6 @@ namespace HIR {
return false;
}
- size_t get_field_ofs(size_t idx, const ::std::vector<size_t>& other_idx, TypeRef& ty) const;
-
friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& x);
};
diff --git a/tools/standalone_miri/lex.cpp b/tools/standalone_miri/lex.cpp
index 48a9e0cd..8fc77f7a 100644
--- a/tools/standalone_miri/lex.cpp
+++ b/tools/standalone_miri/lex.cpp
@@ -11,11 +11,11 @@ bool Token::operator==(TokenClass tc) const
}
bool Token::operator==(char c) const
{
- return this->strval.size() == 1 && this->strval[0] == c;
+ return (this->type == TokenClass::Ident || this->type == TokenClass::Symbol) && this->strval.size() == 1 && this->strval[0] == c;
}
bool Token::operator==(const char* s) const
{
- return this->strval == s;
+ return (this->type == TokenClass::Ident || this->type == TokenClass::Symbol) && this->strval == s;
}
uint64_t Token::integer() const
@@ -56,6 +56,9 @@ double Token::real() const
case TokenClass::ByteString:
os << "b\"" << x.strval << "\"";
break;
+ case TokenClass::Lifetime:
+ os << "'" << x.strval << "\"";
+ break;
}
return os;
}
@@ -95,6 +98,7 @@ Token Lexer::consume()
auto rv = ::std::move(m_cur);
advance();
+ //::std::cout << *this << "Lexer::consume " << rv << " -> " << m_cur << ::std::endl;
return rv;
}
@@ -349,6 +353,23 @@ void Lexer::advance()
auto val = this->parse_string();
m_cur = Token { TokenClass::String, ::std::move(val) };
}
+ else if( ch == '\'')
+ {
+ ::std::string val;
+ ch = m_if.get();
+ while( ch == '_' || ::std::isalnum(ch) )
+ {
+ val += ch;
+ ch = m_if.get();
+ }
+ m_if.unget();
+ if( val == "" )
+ {
+ ::std::cerr << *this << "Empty lifetime name";
+ throw "ERROR";
+ }
+ m_cur = Token { TokenClass::Lifetime, ::std::move(val) };
+ }
else
{
switch(ch)
@@ -390,6 +411,10 @@ void Lexer::advance()
{
m_cur = Token { TokenClass::Symbol, "<<" };
}
+ else if( ch == '=' )
+ {
+ m_cur = Token { TokenClass::Symbol, "<=" };
+ }
else
{
m_if.unget();
diff --git a/tools/standalone_miri/lex.hpp b/tools/standalone_miri/lex.hpp
index 95130111..cc1429f7 100644
--- a/tools/standalone_miri/lex.hpp
+++ b/tools/standalone_miri/lex.hpp
@@ -14,6 +14,7 @@ enum class TokenClass
Real,
String,
ByteString,
+ Lifetime,
};
struct Token
diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp
index a75e753f..deed08be 100644
--- a/tools/standalone_miri/main.cpp
+++ b/tools/standalone_miri/main.cpp
@@ -1,28 +1,36 @@
-//
-//
-//
+/*
+ * mrustc Standalone MIRI
+ * - by John Hodge (Mutabah)
+ *
+ * main.cpp
+ * - Program entrypoint
+ */
#include <iostream>
#include "module_tree.hpp"
#include "value.hpp"
#include <algorithm>
#include <iomanip>
#include "debug.hpp"
-#ifdef _WIN32
-# define NOMINMAX
-# include <Windows.h>
-#endif
+#include "miri.hpp"
+
struct ProgramOptions
{
::std::string infile;
+ //TODO: Architecture file
+ //::std::string archname;
+ //TODO: Loadable FFI descriptions
+ //::std::vector<const char*> ffi_api_files;
+
+ // Output logfile
+ ::std::string logfile;
+ // Arguments for the program
+ ::std::vector<const char*> args;
int parse(int argc, const char* argv[]);
+ void show_help(const char* prog) const;
};
-Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args);
-Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& abi, ::std::vector<Value> args);
-Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector<Value> args);
-
int main(int argc, const char* argv[])
{
ProgramOptions opts;
@@ -32,1914 +40,150 @@ int main(int argc, const char* argv[])
return 1;
}
- auto tree = ModuleTree {};
-
- tree.load_file(opts.infile);
-
- auto val_argc = Value( ::HIR::TypeRef{RawType::I32} );
- ::HIR::TypeRef argv_ty { RawType::I8 };
- argv_ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, 0 });
- argv_ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, 0 });
- auto val_argv = Value(argv_ty);
- val_argc.write_bytes(0, "\0\0\0", 4);
- val_argv.write_bytes(0, "\0\0\0\0\0\0\0", argv_ty.get_size());
+ // Configure logging
+ if( opts.logfile != "" )
+ {
+ DebugSink::set_output_file(opts.logfile);
+ }
+ // Load HIR tree
+ auto tree = ModuleTree {};
try
{
- ::std::vector<Value> args;
- args.push_back(::std::move(val_argc));
- args.push_back(::std::move(val_argv));
- auto rv = MIRI_Invoke( tree, tree.find_lang_item("start"), ::std::move(args) );
- ::std::cout << rv << ::std::endl;
+ tree.load_file(opts.infile);
}
catch(const DebugExceptionTodo& /*e*/)
{
::std::cerr << "TODO Hit" << ::std::endl;
+ if(opts.logfile != "")
+ {
+ ::std::cerr << "- See '" << opts.logfile << "' for details" << ::std::endl;
+ }
return 1;
}
catch(const DebugExceptionError& /*e*/)
{
::std::cerr << "Error encountered" << ::std::endl;
- return 1;
- }
-
- return 0;
-}
-class PrimitiveValue
-{
-public:
- virtual ~PrimitiveValue() {}
-
- virtual bool add(const PrimitiveValue& v) = 0;
- virtual bool subtract(const PrimitiveValue& v) = 0;
- virtual bool multiply(const PrimitiveValue& v) = 0;
- virtual bool divide(const PrimitiveValue& v) = 0;
- virtual bool modulo(const PrimitiveValue& v) = 0;
- virtual void write_to_value(Value& tgt, size_t ofs) const = 0;
-
- template<typename T>
- const T& check(const char* opname) const
- {
- const auto* xp = dynamic_cast<const T*>(this);
- LOG_ASSERT(xp, "Attempting to " << opname << " mismatched types, expected " << typeid(T).name() << " got " << typeid(*this).name());
- return *xp;
- }
-};
-template<typename T>
-struct PrimitiveUInt:
- public PrimitiveValue
-{
- typedef PrimitiveUInt<T> Self;
- T v;
-
- PrimitiveUInt(T v): v(v) {}
- ~PrimitiveUInt() override {}
-
- bool add(const PrimitiveValue& x) override {
- const auto* xp = &x.check<Self>("add");
- T newv = this->v + xp->v;
- bool did_overflow = newv < this->v;
- this->v = newv;
- return !did_overflow;
- }
- bool subtract(const PrimitiveValue& x) override {
- const auto* xp = &x.check<Self>("subtract");
- T newv = this->v - xp->v;
- bool did_overflow = newv > this->v;
- this->v = newv;
- return !did_overflow;
- }
- bool multiply(const PrimitiveValue& x) override {
- const auto* xp = &x.check<Self>("multiply");
- T newv = this->v * xp->v;
- bool did_overflow = newv < this->v && newv < xp->v;
- this->v = newv;
- return !did_overflow;
- }
- bool divide(const PrimitiveValue& x) override {
- const auto* xp = &x.check<Self>("divide");
- if(xp->v == 0) return false;
- T newv = this->v / xp->v;
- this->v = newv;
- return true;
- }
- bool modulo(const PrimitiveValue& x) override {
- const auto* xp = &x.check<Self>("modulo");
- if(xp->v == 0) return false;
- T newv = this->v % xp->v;
- this->v = newv;
- return true;
- }
-};
-struct PrimitiveU64: public PrimitiveUInt<uint64_t>
-{
- PrimitiveU64(uint64_t v): PrimitiveUInt(v) {}
- void write_to_value(Value& tgt, size_t ofs) const override {
- tgt.write_u64(ofs, this->v);
- }
-};
-struct PrimitiveU32: public PrimitiveUInt<uint32_t>
-{
- PrimitiveU32(uint32_t v): PrimitiveUInt(v) {}
- void write_to_value(Value& tgt, size_t ofs) const override {
- tgt.write_u32(ofs, this->v);
- }
-};
-template<typename T>
-struct PrimitiveSInt:
- public PrimitiveValue
-{
- typedef PrimitiveSInt<T> Self;
- T v;
-
- PrimitiveSInt(T v): v(v) {}
- ~PrimitiveSInt() override {}
-
- // TODO: Make this correct.
- bool add(const PrimitiveValue& x) override {
- const auto* xp = &x.check<Self>("add");
- T newv = this->v + xp->v;
- bool did_overflow = newv < this->v;
- this->v = newv;
- return !did_overflow;
- }
- bool subtract(const PrimitiveValue& x) override {
- const auto* xp = &x.check<Self>("subtract");
- T newv = this->v - xp->v;
- bool did_overflow = newv > this->v;
- this->v = newv;
- return !did_overflow;
- }
- bool multiply(const PrimitiveValue& x) override {
- const auto* xp = &x.check<Self>("multiply");
- T newv = this->v * xp->v;
- bool did_overflow = newv < this->v && newv < xp->v;
- this->v = newv;
- return !did_overflow;
- }
- bool divide(const PrimitiveValue& x) override {
- const auto* xp = &x.check<Self>("divide");
- if(xp->v == 0) return false;
- T newv = this->v / xp->v;
- this->v = newv;
- return true;
- }
- bool modulo(const PrimitiveValue& x) override {
- const auto* xp = &x.check<Self>("modulo");
- if(xp->v == 0) return false;
- T newv = this->v % xp->v;
- this->v = newv;
- return true;
- }
-};
-struct PrimitiveI64: public PrimitiveSInt<int64_t>
-{
- PrimitiveI64(int64_t v): PrimitiveSInt(v) {}
- void write_to_value(Value& tgt, size_t ofs) const override {
- tgt.write_i64(ofs, this->v);
- }
-};
-struct PrimitiveI32: public PrimitiveSInt<int32_t>
-{
- PrimitiveI32(int32_t v): PrimitiveSInt(v) {}
- void write_to_value(Value& tgt, size_t ofs) const override {
- tgt.write_i32(ofs, this->v);
- }
-};
-
-class PrimitiveValueVirt
-{
- uint64_t buf[3]; // Allows i128 plus a vtable pointer
- PrimitiveValueVirt() {}
-public:
- // HACK: No copy/move constructors, assumes that contained data is always POD
- ~PrimitiveValueVirt() {
- reinterpret_cast<PrimitiveValue*>(&this->buf)->~PrimitiveValue();
- }
- PrimitiveValue& get() { return *reinterpret_cast<PrimitiveValue*>(&this->buf); }
- const PrimitiveValue& get() const { return *reinterpret_cast<const PrimitiveValue*>(&this->buf); }
-
- static PrimitiveValueVirt from_value(const ::HIR::TypeRef& t, const ValueRef& v) {
- PrimitiveValueVirt rv;
- LOG_ASSERT(t.wrappers.empty(), "PrimitiveValueVirt::from_value: " << t);
- switch(t.inner_type)
- {
- case RawType::U32:
- new(&rv.buf) PrimitiveU32(v.read_u32(0));
- break;
- case RawType::U64:
- new(&rv.buf) PrimitiveU64(v.read_u64(0));
- break;
- case RawType::USize:
- if( POINTER_SIZE == 8 )
- new(&rv.buf) PrimitiveU64(v.read_u64(0));
- else
- new(&rv.buf) PrimitiveU32(v.read_u32(0));
- break;
-
- case RawType::I32:
- new(&rv.buf) PrimitiveI32(v.read_i32(0));
- break;
- case RawType::I64:
- new(&rv.buf) PrimitiveI64(v.read_i64(0));
- break;
- case RawType::ISize:
- if( POINTER_SIZE == 8 )
- new(&rv.buf) PrimitiveI64(v.read_i64(0));
- else
- new(&rv.buf) PrimitiveI32(v.read_i32(0));
- break;
- default:
- LOG_TODO("PrimitiveValueVirt::from_value: " << t);
- }
- return rv;
- }
-};
-
-struct Ops {
- template<typename T>
- static int do_compare(T l, T r) {
- if( l == r ) {
- return 0;
- }
- else if( !(l != r) ) {
- // Special return value for NaN w/ NaN
- return 2;
- }
- else if( l < r ) {
- return -1;
- }
- else {
- return 1;
- }
- }
- template<typename T>
- static T do_bitwise(T l, T r, ::MIR::eBinOp op) {
- switch(op)
- {
- case ::MIR::eBinOp::BIT_AND: return l & r;
- case ::MIR::eBinOp::BIT_OR: return l | r;
- case ::MIR::eBinOp::BIT_XOR: return l ^ r;
- case ::MIR::eBinOp::BIT_SHL: return l << r;
- case ::MIR::eBinOp::BIT_SHR: return l >> r;
- default:
- LOG_BUG("Unexpected operation in Ops::do_bitwise");
- }
- }
-};
-
-namespace
-{
-
- void drop_value(ModuleTree& modtree, Value ptr, const ::HIR::TypeRef& ty)
- {
- if( ty.wrappers.empty() )
- {
- if( ty.inner_type == RawType::Composite )
- {
- if( ty.composite_type->drop_glue != ::HIR::Path() )
- {
- LOG_DEBUG("Drop - " << ty);
-
- MIRI_Invoke(modtree, ty.composite_type->drop_glue, { ptr });
- }
- else
- {
- // No drop glue
- }
- }
- else if( ty.inner_type == RawType::TraitObject )
- {
- LOG_TODO("Drop - " << ty << " - trait object");
- }
- else
- {
- // No destructor
- }
- }
- else if( ty.wrappers[0].type == TypeWrapper::Ty::Borrow )
+ if(opts.logfile != "")
{
- if( ty.wrappers[0].size == static_cast<size_t>(::HIR::BorrowType::Move) )
- {
- LOG_TODO("Drop - " << ty << " - dereference and go to inner");
- // TODO: Clear validity on the entire inner value.
- }
- else
- {
- // No destructor
- }
- }
- // TODO: Arrays
- else
- {
- LOG_TODO("Drop - " << ty << " - array?");
+ ::std::cerr << "- See '" << opts.logfile << "' for details" << ::std::endl;
}
+ return 1;
}
-}
-
-Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args)
-{
- Value ret;
-
- const auto& fcn = modtree.get_function(path);
-
-
- // TODO: Support overriding certain functions
- {
- if( path == ::HIR::SimplePath { "std", { "sys", "imp", "c", "SetThreadStackGuarantee" } } )
- {
- ret = Value(::HIR::TypeRef{RawType::I32});
- ret.write_i32(0, 120); // ERROR_CALL_NOT_IMPLEMENTED
- return ret;
- }
- }
-
- if( fcn.external.link_name != "" )
- {
- // External function!
- ret = MIRI_Invoke_Extern(fcn.external.link_name, fcn.external.link_abi, ::std::move(args));
- LOG_DEBUG(path << " = " << ret);
- return ret;
- }
-
- TRACE_FUNCTION_R(path, path << " = " << ret);
- for(size_t i = 0; i < args.size(); i ++)
+ // Create argc/argv based on input arguments
+ auto argv_alloc = Allocation::new_alloc((1 + opts.args.size()) * POINTER_SIZE);
+ argv_alloc->write_usize(0 * POINTER_SIZE, 0);
+ argv_alloc->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer { "", (void*)(opts.infile.c_str()), opts.infile.size() + 1 }) });
+ for(size_t i = 0; i < opts.args.size(); i ++)
{
- LOG_DEBUG("- Argument(" << i << ") = " << args[i]);
+ argv_alloc->write_usize((1 + i) * POINTER_SIZE, 0);
+ argv_alloc->relocations.push_back({ (1 + i) * POINTER_SIZE, RelocationPtr::new_ffi({ "", (void*)(opts.args[0]), ::std::strlen(opts.args[0]) + 1 }) });
}
+
+ // Construct argc/argv values
+ auto val_argc = Value::new_isize(1 + opts.args.size());
+ auto argv_ty = ::HIR::TypeRef(RawType::I8).wrap(TypeWrapper::Ty::Pointer, 0 ).wrap(TypeWrapper::Ty::Pointer, 0);
+ auto val_argv = Value::new_pointer(argv_ty, 0, RelocationPtr::new_alloc(argv_alloc));
- ret = Value(fcn.ret_ty == RawType::Unreachable ? ::HIR::TypeRef() : fcn.ret_ty);
-
- struct State
+ // Catch various exceptions from the interpreter
+ try
{
- ModuleTree& modtree;
- const Function& fcn;
- Value& ret;
+ InterpreterThread root_thread(tree);
+
::std::vector<Value> args;
- ::std::vector<Value> locals;
- ::std::vector<bool> drop_flags;
-
- State(ModuleTree& modtree, const Function& fcn, Value& ret, ::std::vector<Value> args):
- modtree(modtree),
- fcn(fcn),
- ret(ret),
- args(::std::move(args)),
- drop_flags(fcn.m_mir.drop_flags)
- {
- locals.reserve(fcn.m_mir.locals.size());
- for(const auto& ty : fcn.m_mir.locals)
- {
- if( ty == RawType::Unreachable ) {
- // HACK: Locals can be !, but they can NEVER be accessed
- locals.push_back(Value());
- }
- else {
- locals.push_back(Value(ty));
- }
- }
- }
-
- ValueRef get_value_and_type(const ::MIR::LValue& lv, ::HIR::TypeRef& ty)
- {
- switch(lv.tag())
- {
- case ::MIR::LValue::TAGDEAD: throw "";
- TU_ARM(lv, Return, _e) {
- ty = fcn.ret_ty;
- return ValueRef(ret, 0, ret.size());
- } break;
- TU_ARM(lv, Local, e) {
- ty = fcn.m_mir.locals.at(e);
- return ValueRef(locals.at(e), 0, locals.at(e).size());
- } break;
- TU_ARM(lv, Argument, e) {
- ty = fcn.args.at(e.idx);
- return ValueRef(args.at(e.idx), 0, args.at(e.idx).size());
- } break;
- TU_ARM(lv, Static, e) {
- // TODO: Type!
- return ValueRef(modtree.get_static(e), 0, modtree.get_static(e).size());
- } break;
- TU_ARM(lv, Index, e) {
- auto idx = get_value_ref(*e.idx).read_usize(0);
- ::HIR::TypeRef array_ty;
- auto base_val = get_value_and_type(*e.val, array_ty);
- if( array_ty.wrappers.empty() )
- throw "ERROR";
- if( array_ty.wrappers.front().type == TypeWrapper::Ty::Array )
- {
- ty = array_ty.get_inner();
- base_val.m_offset += ty.get_size() * idx;
- return base_val;
- }
- else if( array_ty.wrappers.front().type == TypeWrapper::Ty::Slice )
- {
- throw "TODO";
- }
- else
- {
- throw "ERROR";
- }
- } break;
- TU_ARM(lv, Field, e) {
- ::HIR::TypeRef composite_ty;
- auto base_val = get_value_and_type(*e.val, composite_ty);
- // TODO: if there's metadata present in the base, but the inner doesn't have metadata, clear the metadata
- size_t inner_ofs;
- ty = composite_ty.get_field(e.field_index, inner_ofs);
- LOG_DEBUG("Field - " << composite_ty << "#" << e.field_index << " = @" << inner_ofs << " " << ty);
- base_val.m_offset += inner_ofs;
- if( !ty.get_meta_type() )
- {
- LOG_ASSERT(base_val.m_size >= ty.get_size(), "Field didn't fit in the value - " << ty.get_size() << " required, but " << base_val.m_size << " avail");
- base_val.m_size = ty.get_size();
- }
- return base_val;
- }
- TU_ARM(lv, Downcast, e) {
- ::HIR::TypeRef composite_ty;
- auto base_val = get_value_and_type(*e.val, composite_ty);
- LOG_DEBUG("Downcast - " << composite_ty);
-
- size_t inner_ofs;
- ty = composite_ty.get_field(e.variant_index, inner_ofs);
- base_val.m_offset += inner_ofs;
- return base_val;
- }
- TU_ARM(lv, Deref, e) {
- ::HIR::TypeRef ptr_ty;
- auto val = get_value_and_type(*e.val, ptr_ty);
- ty = ptr_ty.get_inner();
- LOG_DEBUG("val = " << val);
-
- LOG_ASSERT(val.m_size >= POINTER_SIZE, "Deref of a value that doesn't fit a pointer - " << ty);
- size_t ofs = val.read_usize(0);
-
- // There MUST be a relocation at this point with a valid allocation.
- auto& val_alloc = val.m_alloc ? val.m_alloc : val.m_value->allocation;
- LOG_ASSERT(val_alloc, "Deref of a value with no allocation (hence no relocations)");
- LOG_ASSERT(val_alloc.is_alloc(), "Deref of a value with a non-data allocation");
- LOG_TRACE("Deref " << val_alloc.alloc() << " + " << ofs << " to give value of type " << ty);
- auto alloc = val_alloc.alloc().get_relocation(val.m_offset);
- LOG_ASSERT(alloc, "Deref of a value with no relocation");
- if( alloc.is_alloc() )
- {
- LOG_DEBUG("> " << lv << " alloc=" << alloc.alloc());
- }
- size_t size;
-
- const auto* meta_ty = ty.get_meta_type();
- ::std::shared_ptr<Value> meta_val;
- // If the type has metadata, store it.
- if( meta_ty )
- {
- auto meta_size = meta_ty->get_size();
- LOG_ASSERT(val.m_size == POINTER_SIZE + meta_size, "Deref of " << ty << ", but pointer isn't correct size");
- meta_val = ::std::make_shared<Value>( val.read_value(POINTER_SIZE, meta_size) );
-
- // TODO: Get a more sane size from the metadata
- LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs);
- size = alloc.get_size() - ofs;
- }
- else
- {
- LOG_ASSERT(val.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value (size=" << val.m_size << ") - " << val << ": " << ptr_ty);
- size = ty.get_size();
- }
-
- auto rv = ValueRef(::std::move(alloc), ofs, size);
- rv.m_metadata = ::std::move(meta_val);
- return rv;
- } break;
- }
- throw "";
- }
- ValueRef get_value_ref(const ::MIR::LValue& lv)
- {
- ::HIR::TypeRef tmp;
- return get_value_and_type(lv, tmp);
- }
-
- ::HIR::TypeRef get_lvalue_ty(const ::MIR::LValue& lv)
- {
- ::HIR::TypeRef ty;
- get_value_and_type(lv, ty);
- return ty;
- }
-
- Value read_lvalue_with_ty(const ::MIR::LValue& lv, ::HIR::TypeRef& ty)
- {
- auto base_value = get_value_and_type(lv, ty);
-
- return base_value.read_value(0, ty.get_size());
- }
- Value read_lvalue(const ::MIR::LValue& lv)
- {
- ::HIR::TypeRef ty;
- return read_lvalue_with_ty(lv, ty);
- }
- void write_lvalue(const ::MIR::LValue& lv, Value val)
- {
- //LOG_DEBUG(lv << " = " << val);
- ::HIR::TypeRef ty;
- auto base_value = get_value_and_type(lv, ty);
-
- if(base_value.m_alloc) {
- base_value.m_alloc.alloc().write_value(base_value.m_offset, ::std::move(val));
- }
- else {
- base_value.m_value->write_value(base_value.m_offset, ::std::move(val));
- }
- }
-
- Value const_to_value(const ::MIR::Constant& c, ::HIR::TypeRef& ty)
- {
- switch(c.tag())
- {
- case ::MIR::Constant::TAGDEAD: throw "";
- TU_ARM(c, Int, ce) {
- ty = ::HIR::TypeRef(ce.t);
- Value val = Value(ty);
- val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian
- // TODO: If the write was clipped, sign-extend
- return val;
- } break;
- TU_ARM(c, Uint, ce) {
- ty = ::HIR::TypeRef(ce.t);
- Value val = Value(ty);
- val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian
- return val;
- } break;
- TU_ARM(c, Bool, ce) {
- Value val = Value(::HIR::TypeRef { RawType::Bool });
- val.write_bytes(0, &ce.v, 1);
- return val;
- } break;
- TU_ARM(c, Float, ce) {
- ty = ::HIR::TypeRef(ce.t);
- Value val = Value(ty);
- if( ce.t.raw_type == RawType::F64 ) {
- val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian/format?
- }
- else if( ce.t.raw_type == RawType::F32 ) {
- float v = static_cast<float>(ce.v);
- val.write_bytes(0, &v, ::std::min(ty.get_size(), sizeof(v))); // TODO: Endian/format?
- }
- else {
- throw ::std::runtime_error("BUG: Invalid type in Constant::Float");
- }
- return val;
- } break;
- TU_ARM(c, Const, ce) {
- LOG_BUG("Constant::Const in mmir");
- } break;
- TU_ARM(c, Bytes, ce) {
- LOG_TODO("Constant::Bytes");
- } break;
- TU_ARM(c, StaticString, ce) {
- ty = ::HIR::TypeRef(RawType::Str);
- ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 });
- Value val = Value(ty);
- val.write_usize(0, 0);
- val.write_usize(POINTER_SIZE, ce.size());
- val.allocation.alloc().relocations.push_back(Relocation { 0, AllocationPtr::new_string(&ce) });
- LOG_DEBUG(c << " = " << val);
- //return Value::new_dataptr(ce.data());
- return val;
- } break;
- TU_ARM(c, ItemAddr, ce) {
- // Create a value with a special backing allocation of zero size that references the specified item.
- if( const auto* fn = modtree.get_function_opt(ce) ) {
- return Value::new_fnptr(ce);
- }
- LOG_TODO("Constant::ItemAddr - statics?");
- } break;
- }
- throw "";
- }
- Value const_to_value(const ::MIR::Constant& c)
- {
- ::HIR::TypeRef ty;
- return const_to_value(c, ty);
- }
- Value param_to_value(const ::MIR::Param& p, ::HIR::TypeRef& ty)
- {
- switch(p.tag())
- {
- case ::MIR::Param::TAGDEAD: throw "";
- TU_ARM(p, Constant, pe)
- return const_to_value(pe, ty);
- TU_ARM(p, LValue, pe)
- return read_lvalue_with_ty(pe, ty);
- }
- throw "";
- }
- Value param_to_value(const ::MIR::Param& p)
- {
- ::HIR::TypeRef ty;
- return param_to_value(p, ty);
- }
-
- ValueRef get_value_ref_param(const ::MIR::Param& p, Value& tmp, ::HIR::TypeRef& ty)
- {
- switch(p.tag())
- {
- case ::MIR::Param::TAGDEAD: throw "";
- TU_ARM(p, Constant, pe)
- tmp = const_to_value(pe, ty);
- return ValueRef(tmp, 0, ty.get_size());
- TU_ARM(p, LValue, pe)
- return get_value_and_type(pe, ty);
- }
- throw "";
- }
- } state { modtree, fcn, ret, ::std::move(args) };
-
- size_t bb_idx = 0;
- for(;;)
- {
- const auto& bb = fcn.m_mir.blocks.at(bb_idx);
-
- for(const auto& stmt : bb.statements)
- {
- LOG_DEBUG("BB" << bb_idx << "/" << (&stmt - bb.statements.data()) << ": " << stmt);
- switch(stmt.tag())
- {
- case ::MIR::Statement::TAGDEAD: throw "";
- TU_ARM(stmt, Assign, se) {
- Value new_val;
- switch(se.src.tag())
- {
- case ::MIR::RValue::TAGDEAD: throw "";
- TU_ARM(se.src, Use, re) {
- new_val = state.read_lvalue(re);
- } break;
- TU_ARM(se.src, Constant, re) {
- new_val = state.const_to_value(re);
- } break;
- TU_ARM(se.src, Borrow, re) {
- ::HIR::TypeRef src_ty;
- ValueRef src_base_value = state.get_value_and_type(re.val, src_ty);
- auto alloc = src_base_value.m_alloc;
- if( !alloc )
- {
- if( !src_base_value.m_value->allocation )
- {
- src_base_value.m_value->create_allocation();
- }
- alloc = AllocationPtr(src_base_value.m_value->allocation);
- }
- if( alloc.is_alloc() )
- LOG_DEBUG("- alloc=" << alloc << " (" << alloc.alloc() << ")");
- else
- LOG_DEBUG("- alloc=" << alloc);
- size_t ofs = src_base_value.m_offset;
- const auto* meta = src_ty.get_meta_type();
- bool is_slice_like = src_ty.has_slice_meta();
- src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast<size_t>(re.type) });
-
- new_val = Value(src_ty);
- // ^ Pointer value
- new_val.write_usize(0, ofs);
- if( meta )
- {
- LOG_ASSERT(src_base_value.m_metadata, "Borrow of an unsized value, but no metadata avaliable");
- new_val.write_value(POINTER_SIZE, *src_base_value.m_metadata);
- }
- // - Add the relocation after writing the value (writing clears the relocations)
- new_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) });
- } break;
- TU_ARM(se.src, Cast, re) {
- // Determine the type of cast, is it a reinterpret or is it a value transform?
- // - Float <-> integer is a transform, anything else should be a reinterpret.
- ::HIR::TypeRef src_ty;
- auto src_value = state.get_value_and_type(re.val, src_ty);
-
- new_val = Value(re.type);
- if( re.type == src_ty )
- {
- // No-op cast
- new_val = src_value.read_value(0, re.type.get_size());
- }
- else if( !re.type.wrappers.empty() )
- {
- // Destination can only be a raw pointer
- if( re.type.wrappers.at(0).type != TypeWrapper::Ty::Pointer ) {
- throw "ERROR";
- }
- if( !src_ty.wrappers.empty() )
- {
- // Source can be either
- if( src_ty.wrappers.at(0).type != TypeWrapper::Ty::Pointer
- && src_ty.wrappers.at(0).type != TypeWrapper::Ty::Borrow ) {
- throw "ERROR";
- }
-
- if( src_ty.get_size() > re.type.get_size() ) {
- // TODO: How to casting fat to thin?
- //LOG_TODO("Handle casting fat to thin, " << src_ty << " -> " << re.type);
- new_val = src_value.read_value(0, re.type.get_size());
- }
- else
- {
- new_val = src_value.read_value(0, re.type.get_size());
- }
- }
- else
- {
- if( src_ty == RawType::Function )
- {
- }
- else if( src_ty == RawType::USize )
- {
- }
- else
- {
- ::std::cerr << "ERROR: Trying to pointer (" << re.type <<" ) from invalid type (" << src_ty << ")\n";
- throw "ERROR";
- }
- new_val = src_value.read_value(0, re.type.get_size());
- }
- }
- else if( !src_ty.wrappers.empty() )
- {
- // TODO: top wrapper MUST be a pointer
- if( src_ty.wrappers.at(0).type != TypeWrapper::Ty::Pointer
- && src_ty.wrappers.at(0).type != TypeWrapper::Ty::Borrow ) {
- throw "ERROR";
- }
- // TODO: MUST be a thin pointer?
-
- // TODO: MUST be an integer (usize only?)
- if( re.type != RawType::USize && re.type != RawType::ISize ) {
- LOG_ERROR("Casting from a pointer to non-usize - " << re.type << " to " << src_ty);
- throw "ERROR";
- }
- new_val = src_value.read_value(0, re.type.get_size());
- }
- else
- {
- // TODO: What happens if there'a cast of something with a relocation?
- switch(re.type.inner_type)
- {
- case RawType::Unreachable: throw "BUG";
- case RawType::Composite: throw "ERROR";
- case RawType::TraitObject: throw "ERROR";
- case RawType::Function: throw "ERROR";
- case RawType::Str: throw "ERROR";
- case RawType::Unit: throw "ERROR";
- case RawType::F32: {
- float dst_val = 0.0;
- // Can be an integer, or F64 (pointer is impossible atm)
- switch(src_ty.inner_type)
- {
- case RawType::Unreachable: throw "BUG";
- case RawType::Composite: throw "ERROR";
- case RawType::TraitObject: throw "ERROR";
- case RawType::Function: throw "ERROR";
- case RawType::Char: throw "ERROR";
- case RawType::Str: throw "ERROR";
- case RawType::Unit: throw "ERROR";
- case RawType::Bool: throw "ERROR";
- case RawType::F32: throw "BUG";
- case RawType::F64: dst_val = static_cast<float>( src_value.read_f64(0) ); break;
- case RawType::USize: throw "TODO";// /*dst_val = src_value.read_usize();*/ break;
- case RawType::ISize: throw "TODO";// /*dst_val = src_value.read_isize();*/ break;
- case RawType::U8: dst_val = static_cast<float>( src_value.read_u8 (0) ); break;
- case RawType::I8: dst_val = static_cast<float>( src_value.read_i8 (0) ); break;
- case RawType::U16: dst_val = static_cast<float>( src_value.read_u16(0) ); break;
- case RawType::I16: dst_val = static_cast<float>( src_value.read_i16(0) ); break;
- case RawType::U32: dst_val = static_cast<float>( src_value.read_u32(0) ); break;
- case RawType::I32: dst_val = static_cast<float>( src_value.read_i32(0) ); break;
- case RawType::U64: dst_val = static_cast<float>( src_value.read_u64(0) ); break;
- case RawType::I64: dst_val = static_cast<float>( src_value.read_i64(0) ); break;
- case RawType::U128: throw "TODO";// /*dst_val = src_value.read_u128();*/ break;
- case RawType::I128: throw "TODO";// /*dst_val = src_value.read_i128();*/ break;
- }
- new_val.write_f32(0, dst_val);
- } break;
- case RawType::F64: {
- double dst_val = 0.0;
- // Can be an integer, or F32 (pointer is impossible atm)
- switch(src_ty.inner_type)
- {
- case RawType::Unreachable: throw "BUG";
- case RawType::Composite: throw "ERROR";
- case RawType::TraitObject: throw "ERROR";
- case RawType::Function: throw "ERROR";
- case RawType::Char: throw "ERROR";
- case RawType::Str: throw "ERROR";
- case RawType::Unit: throw "ERROR";
- case RawType::Bool: throw "ERROR";
- case RawType::F64: throw "BUG";
- case RawType::F32: dst_val = static_cast<double>( src_value.read_f32(0) ); break;
- case RawType::USize: dst_val = static_cast<double>( src_value.read_usize(0) ); break;
- case RawType::ISize: dst_val = static_cast<double>( src_value.read_isize(0) ); break;
- case RawType::U8: dst_val = static_cast<double>( src_value.read_u8 (0) ); break;
- case RawType::I8: dst_val = static_cast<double>( src_value.read_i8 (0) ); break;
- case RawType::U16: dst_val = static_cast<double>( src_value.read_u16(0) ); break;
- case RawType::I16: dst_val = static_cast<double>( src_value.read_i16(0) ); break;
- case RawType::U32: dst_val = static_cast<double>( src_value.read_u32(0) ); break;
- case RawType::I32: dst_val = static_cast<double>( src_value.read_i32(0) ); break;
- case RawType::U64: dst_val = static_cast<double>( src_value.read_u64(0) ); break;
- case RawType::I64: dst_val = static_cast<double>( src_value.read_i64(0) ); break;
- case RawType::U128: throw "TODO"; /*dst_val = src_value.read_u128();*/ break;
- case RawType::I128: throw "TODO"; /*dst_val = src_value.read_i128();*/ break;
- }
- new_val.write_f64(0, dst_val);
- } break;
- case RawType::Bool:
- LOG_TODO("Cast to " << re.type);
- case RawType::Char:
- LOG_TODO("Cast to " << re.type);
- case RawType::USize:
- case RawType::U8:
- case RawType::U16:
- case RawType::U32:
- case RawType::U64:
- case RawType::ISize:
- case RawType::I8:
- case RawType::I16:
- case RawType::I32:
- case RawType::I64:
- {
- uint64_t dst_val = 0;
- // Can be an integer, or F32 (pointer is impossible atm)
- switch(src_ty.inner_type)
- {
- case RawType::Unreachable:
- LOG_BUG("Casting unreachable");
- case RawType::TraitObject:
- case RawType::Str:
- LOG_FATAL("Cast of unsized type - " << src_ty);
- case RawType::Function:
- LOG_ASSERT(re.type.inner_type == RawType::USize, "Function pointers can only be casted to usize, instead " << re.type);
- new_val = src_value.read_value(0, re.type.get_size());
- break;
- case RawType::Char:
- LOG_ASSERT(re.type.inner_type == RawType::U32, "Char can only be casted to u32, instead " << re.type);
- new_val = src_value.read_value(0, 4);
- break;
- case RawType::Unit:
- LOG_FATAL("Cast of unit");
- case RawType::Composite: {
- const auto& dt = *src_ty.composite_type;
- if( dt.variants.size() == 0 ) {
- LOG_FATAL("Cast of composite - " << src_ty);
- }
- // TODO: Check that all variants have the same tag offset
- LOG_ASSERT(dt.fields.size() == 1, "");
- LOG_ASSERT(dt.fields[0].first == 0, "");
- for(size_t i = 0; i < dt.variants.size(); i ++ ) {
- LOG_ASSERT(dt.variants[i].base_field == 0, "");
- LOG_ASSERT(dt.variants[i].field_path.empty(), "");
- }
- ::HIR::TypeRef tag_ty = dt.fields[0].second;
- LOG_ASSERT(tag_ty.wrappers.empty(), "");
- switch(tag_ty.inner_type)
- {
- case RawType::USize:
- dst_val = static_cast<uint64_t>( src_value.read_usize(0) );
- if(0)
- case RawType::ISize:
- dst_val = static_cast<uint64_t>( src_value.read_isize(0) );
- if(0)
- case RawType::U8:
- dst_val = static_cast<uint64_t>( src_value.read_u8 (0) );
- if(0)
- case RawType::I8:
- dst_val = static_cast<uint64_t>( src_value.read_i8 (0) );
- if(0)
- case RawType::U16:
- dst_val = static_cast<uint64_t>( src_value.read_u16(0) );
- if(0)
- case RawType::I16:
- dst_val = static_cast<uint64_t>( src_value.read_i16(0) );
- if(0)
- case RawType::U32:
- dst_val = static_cast<uint64_t>( src_value.read_u32(0) );
- if(0)
- case RawType::I32:
- dst_val = static_cast<uint64_t>( src_value.read_i32(0) );
- if(0)
- case RawType::U64:
- dst_val = static_cast<uint64_t>( src_value.read_u64(0) );
- if(0)
- case RawType::I64:
- dst_val = static_cast<uint64_t>( src_value.read_i64(0) );
- break;
- default:
- LOG_FATAL("Bad tag type in cast - " << tag_ty);
- }
- } if(0)
- case RawType::Bool:
- dst_val = static_cast<uint64_t>( src_value.read_u8 (0) );
- if(0)
- case RawType::F64:
- dst_val = static_cast<uint64_t>( src_value.read_f64(0) );
- if(0)
- case RawType::F32:
- dst_val = static_cast<uint64_t>( src_value.read_f32(0) );
- if(0)
- case RawType::USize:
- dst_val = static_cast<uint64_t>( src_value.read_usize(0) );
- if(0)
- case RawType::ISize:
- dst_val = static_cast<uint64_t>( src_value.read_isize(0) );
- if(0)
- case RawType::U8:
- dst_val = static_cast<uint64_t>( src_value.read_u8 (0) );
- if(0)
- case RawType::I8:
- dst_val = static_cast<uint64_t>( src_value.read_i8 (0) );
- if(0)
- case RawType::U16:
- dst_val = static_cast<uint64_t>( src_value.read_u16(0) );
- if(0)
- case RawType::I16:
- dst_val = static_cast<uint64_t>( src_value.read_i16(0) );
- if(0)
- case RawType::U32:
- dst_val = static_cast<uint64_t>( src_value.read_u32(0) );
- if(0)
- case RawType::I32:
- dst_val = static_cast<uint64_t>( src_value.read_i32(0) );
- if(0)
- case RawType::U64:
- dst_val = static_cast<uint64_t>( src_value.read_u64(0) );
- if(0)
- case RawType::I64:
- dst_val = static_cast<uint64_t>( src_value.read_i64(0) );
-
- switch(re.type.inner_type)
- {
- case RawType::USize:
- new_val.write_usize(0, dst_val);
- break;
- case RawType::U8:
- new_val.write_u8(0, static_cast<uint8_t>(dst_val));
- break;
- case RawType::U16:
- new_val.write_u16(0, static_cast<uint16_t>(dst_val));
- break;
- case RawType::U32:
- new_val.write_u32(0, static_cast<uint32_t>(dst_val));
- break;
- case RawType::U64:
- new_val.write_u64(0, dst_val);
- break;
- case RawType::ISize:
- new_val.write_usize(0, static_cast<int64_t>(dst_val));
- break;
- case RawType::I8:
- new_val.write_i8(0, static_cast<int8_t>(dst_val));
- break;
- case RawType::I16:
- new_val.write_i16(0, static_cast<int16_t>(dst_val));
- break;
- case RawType::I32:
- new_val.write_i32(0, static_cast<int32_t>(dst_val));
- break;
- case RawType::I64:
- new_val.write_i64(0, static_cast<int64_t>(dst_val));
- break;
- default:
- throw "";
- }
- break;
- case RawType::U128: throw "TODO"; /*dst_val = src_value.read_u128();*/ break;
- case RawType::I128: throw "TODO"; /*dst_val = src_value.read_i128();*/ break;
- }
- } break;
- case RawType::U128:
- case RawType::I128:
- LOG_TODO("Cast to " << re.type);
- }
- }
- } break;
- TU_ARM(se.src, BinOp, re) {
- ::HIR::TypeRef ty_l, ty_r;
- Value tmp_l, tmp_r;
- auto v_l = state.get_value_ref_param(re.val_l, tmp_l, ty_l);
- auto v_r = state.get_value_ref_param(re.val_r, tmp_r, ty_r);
- LOG_DEBUG(v_l << " (" << ty_l <<") ? " << v_r << " (" << ty_r <<")");
-
- switch(re.op)
- {
- case ::MIR::eBinOp::EQ:
- case ::MIR::eBinOp::NE:
- case ::MIR::eBinOp::GT:
- case ::MIR::eBinOp::GE:
- case ::MIR::eBinOp::LT:
- case ::MIR::eBinOp::LE: {
- LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
- int res = 0;
- // TODO: Handle comparison of the relocations too
-
- const auto& alloc_l = v_l.m_value ? v_l.m_value->allocation : v_l.m_alloc;
- const auto& alloc_r = v_r.m_value ? v_r.m_value->allocation : v_r.m_alloc;
- auto reloc_l = alloc_l ? v_l.get_relocation(v_l.m_offset) : AllocationPtr();
- auto reloc_r = alloc_r ? v_r.get_relocation(v_r.m_offset) : AllocationPtr();
-
- if( reloc_l != reloc_r )
- {
- res = (reloc_l < reloc_r ? -1 : 1);
- }
- LOG_DEBUG("res=" << res << ", " << reloc_l << " ? " << reloc_r);
-
- if( ty_l.wrappers.empty() )
- {
- switch(ty_l.inner_type)
- {
- case RawType::U64: res = res != 0 ? res : Ops::do_compare(v_l.read_u64(0), v_r.read_u64(0)); break;
- case RawType::U32: res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0)); break;
- case RawType::U16: res = res != 0 ? res : Ops::do_compare(v_l.read_u16(0), v_r.read_u16(0)); break;
- case RawType::U8 : res = res != 0 ? res : Ops::do_compare(v_l.read_u8 (0), v_r.read_u8 (0)); break;
- case RawType::I64: res = res != 0 ? res : Ops::do_compare(v_l.read_i64(0), v_r.read_i64(0)); break;
- case RawType::I32: res = res != 0 ? res : Ops::do_compare(v_l.read_i32(0), v_r.read_i32(0)); break;
- case RawType::I16: res = res != 0 ? res : Ops::do_compare(v_l.read_i16(0), v_r.read_i16(0)); break;
- case RawType::I8 : res = res != 0 ? res : Ops::do_compare(v_l.read_i8 (0), v_r.read_i8 (0)); break;
- case RawType::USize: res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); break;
- case RawType::ISize: res = res != 0 ? res : Ops::do_compare(v_l.read_isize(0), v_r.read_isize(0)); break;
- default:
- LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l);
- }
- }
- else if( ty_l.wrappers.front().type == TypeWrapper::Ty::Pointer )
- {
- // TODO: Technically only EQ/NE are valid.
-
- res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0));
-
- // Compare fat metadata.
- if( res == 0 && v_l.m_size > POINTER_SIZE )
- {
- reloc_l = alloc_l ? alloc_l.alloc().get_relocation(POINTER_SIZE) : AllocationPtr();
- reloc_r = alloc_r ? alloc_r.alloc().get_relocation(POINTER_SIZE) : AllocationPtr();
-
- if( res == 0 && reloc_l != reloc_r )
- {
- res = (reloc_l < reloc_r ? -1 : 1);
- }
- res = res != 0 ? res : Ops::do_compare(v_l.read_usize(POINTER_SIZE), v_r.read_usize(POINTER_SIZE));
- }
- }
- else
- {
- LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l);
- }
- bool res_bool;
- switch(re.op)
- {
- case ::MIR::eBinOp::EQ: res_bool = (res == 0); break;
- case ::MIR::eBinOp::NE: res_bool = (res != 0); break;
- case ::MIR::eBinOp::GT: res_bool = (res == 1); break;
- case ::MIR::eBinOp::GE: res_bool = (res == 1 || res == 0); break;
- case ::MIR::eBinOp::LT: res_bool = (res == -1); break;
- case ::MIR::eBinOp::LE: res_bool = (res == -1 || res == 0); break;
- break;
- default:
- LOG_BUG("Unknown comparison");
- }
- new_val = Value(::HIR::TypeRef(RawType::Bool));
- new_val.write_u8(0, res_bool ? 1 : 0);
- } break;
- case ::MIR::eBinOp::BIT_SHL:
- case ::MIR::eBinOp::BIT_SHR: {
- LOG_ASSERT(ty_l.wrappers.empty(), "Bitwise operator on non-primitive - " << ty_l);
- LOG_ASSERT(ty_r.wrappers.empty(), "Bitwise operator with non-primitive - " << ty_r);
- size_t max_bits = ty_r.get_size() * 8;
- uint8_t shift;
- auto check_cast = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast<uint8_t>(v); };
- switch(ty_r.inner_type)
- {
- case RawType::U64: shift = check_cast(v_r.read_u64(0)); break;
- case RawType::U32: shift = check_cast(v_r.read_u32(0)); break;
- case RawType::U16: shift = check_cast(v_r.read_u16(0)); break;
- case RawType::U8 : shift = check_cast(v_r.read_u8 (0)); break;
- case RawType::I64: shift = check_cast(v_r.read_i64(0)); break;
- case RawType::I32: shift = check_cast(v_r.read_i32(0)); break;
- case RawType::I16: shift = check_cast(v_r.read_i16(0)); break;
- case RawType::I8 : shift = check_cast(v_r.read_i8 (0)); break;
- case RawType::USize: shift = check_cast(v_r.read_usize(0)); break;
- case RawType::ISize: shift = check_cast(v_r.read_isize(0)); break;
- default:
- LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r);
- }
- new_val = Value(ty_l);
- switch(ty_l.inner_type)
- {
- case RawType::U64: new_val.write_u64(0, Ops::do_bitwise(v_l.read_u64(0), static_cast<uint64_t>(shift), re.op)); break;
- case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast<uint32_t>(shift), re.op)); break;
- case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast<uint16_t>(shift), re.op)); break;
- case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast<uint8_t >(shift), re.op)); break;
- case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast<uint64_t>(shift), re.op)); break;
- default:
- LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r);
- }
- } break;
- case ::MIR::eBinOp::BIT_AND:
- case ::MIR::eBinOp::BIT_OR:
- case ::MIR::eBinOp::BIT_XOR:
- LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
- LOG_ASSERT(ty_l.wrappers.empty(), "Bitwise operator on non-primitive - " << ty_l);
- new_val = Value(ty_l);
- switch(ty_l.inner_type)
- {
- case RawType::U64:
- new_val.write_u64( 0, Ops::do_bitwise(v_l.read_u64(0), v_r.read_u64(0), re.op) );
- break;
- case RawType::U32:
- new_val.write_u32( 0, static_cast<uint32_t>(Ops::do_bitwise(v_l.read_u32(0), v_r.read_u32(0), re.op)) );
- break;
- case RawType::U16:
- new_val.write_u16( 0, static_cast<uint16_t>(Ops::do_bitwise(v_l.read_u16(0), v_r.read_u16(0), re.op)) );
- break;
- case RawType::U8:
- new_val.write_u8 ( 0, static_cast<uint8_t >(Ops::do_bitwise(v_l.read_u8 (0), v_r.read_u8 (0), re.op)) );
- break;
- case RawType::USize:
- new_val.write_usize( 0, Ops::do_bitwise(v_l.read_usize(0), v_r.read_usize(0), re.op) );
- break;
- default:
- LOG_TODO("BinOp bitwise - " << se.src << " w/ " << ty_l);
- }
-
- break;
- default:
- LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
- auto val_l = PrimitiveValueVirt::from_value(ty_l, v_l);
- auto val_r = PrimitiveValueVirt::from_value(ty_r, v_r);
- switch(re.op)
- {
- case ::MIR::eBinOp::ADD: val_l.get().add( val_r.get() ); break;
- case ::MIR::eBinOp::SUB: val_l.get().subtract( val_r.get() ); break;
- case ::MIR::eBinOp::MUL: val_l.get().multiply( val_r.get() ); break;
- case ::MIR::eBinOp::DIV: val_l.get().divide( val_r.get() ); break;
- case ::MIR::eBinOp::MOD: val_l.get().modulo( val_r.get() ); break;
-
- default:
- LOG_TODO("Unsupported binary operator?");
- }
- new_val = Value(ty_l);
- val_l.get().write_to_value(new_val, 0);
- break;
- }
- } break;
- TU_ARM(se.src, UniOp, re) {
- ::HIR::TypeRef ty;
- auto v = state.get_value_and_type(re.val, ty);
- LOG_ASSERT(ty.wrappers.empty(), "UniOp on wrapped type - " << ty);
- new_val = Value(ty);
- switch(re.op)
- {
- case ::MIR::eUniOp::INV:
- switch(ty.inner_type)
- {
- case RawType::U128:
- LOG_TODO("UniOp::INV U128");
- case RawType::U64:
- new_val.write_u64( 0, ~v.read_u64(0) );
- break;
- case RawType::U32:
- new_val.write_u32( 0, ~v.read_u32(0) );
- break;
- case RawType::U16:
- new_val.write_u16( 0, ~v.read_u16(0) );
- break;
- case RawType::U8:
- new_val.write_u8 ( 0, ~v.read_u8 (0) );
- break;
- case RawType::USize:
- new_val.write_usize( 0, ~v.read_usize(0) );
- break;
- case RawType::Bool:
- new_val.write_u8 ( 0, v.read_u8 (0) == 0 );
- break;
- default:
- LOG_TODO("UniOp::INV - w/ type " << ty);
- }
- break;
- case ::MIR::eUniOp::NEG:
- switch(ty.inner_type)
- {
- case RawType::I128:
- LOG_TODO("UniOp::NEG I128");
- case RawType::I64:
- new_val.write_i64( 0, -v.read_i64(0) );
- break;
- case RawType::I32:
- new_val.write_i32( 0, -v.read_i32(0) );
- break;
- case RawType::I16:
- new_val.write_i16( 0, -v.read_i16(0) );
- break;
- case RawType::I8:
- new_val.write_i8 ( 0, -v.read_i8 (0) );
- break;
- case RawType::ISize:
- new_val.write_isize( 0, -v.read_isize(0) );
- break;
- default:
- LOG_TODO("UniOp::INV - w/ type " << ty);
- }
- break;
- }
- } break;
- TU_ARM(se.src, DstMeta, re) {
- LOG_TODO(stmt);
- } break;
- TU_ARM(se.src, DstPtr, re) {
- LOG_TODO(stmt);
- } break;
- TU_ARM(se.src, MakeDst, re) {
- // - Get target type, just for some assertions
- ::HIR::TypeRef dst_ty;
- state.get_value_and_type(se.dst, dst_ty);
- new_val = Value(dst_ty);
-
- auto ptr = state.param_to_value(re.ptr_val );
- auto meta = state.param_to_value(re.meta_val);
- LOG_DEBUG("ty=" << dst_ty << ", ptr=" << ptr << ", meta=" << meta);
-
- new_val.write_value(0, ::std::move(ptr));
- new_val.write_value(POINTER_SIZE, ::std::move(meta));
- } break;
- TU_ARM(se.src, Tuple, re) {
- ::HIR::TypeRef dst_ty;
- state.get_value_and_type(se.dst, dst_ty);
- new_val = Value(dst_ty);
-
- for(size_t i = 0; i < re.vals.size(); i++)
- {
- auto fld_ofs = dst_ty.composite_type->fields.at(i).first;
- new_val.write_value(fld_ofs, state.param_to_value(re.vals[i]));
- }
- } break;
- TU_ARM(se.src, Array, re) {
- ::HIR::TypeRef dst_ty;
- state.get_value_and_type(se.dst, dst_ty);
- new_val = Value(dst_ty);
- // TODO: Assert that type is an array
- auto inner_ty = dst_ty.get_inner();
- size_t stride = inner_ty.get_size();
-
- size_t ofs = 0;
- for(const auto& v : re.vals)
- {
- new_val.write_value(ofs, state.param_to_value(v));
- ofs += stride;
- }
- } break;
- TU_ARM(se.src, SizedArray, re) {
- ::HIR::TypeRef dst_ty;
- state.get_value_and_type(se.dst, dst_ty);
- new_val = Value(dst_ty);
- // TODO: Assert that type is an array
- auto inner_ty = dst_ty.get_inner();
- size_t stride = inner_ty.get_size();
-
- size_t ofs = 0;
- for(size_t i = 0; i < re.count; i++)
- {
- new_val.write_value(ofs, state.param_to_value(re.val));
- ofs += stride;
- }
- } break;
- TU_ARM(se.src, Variant, re) {
- // 1. Get the composite by path.
- const auto& data_ty = state.modtree.get_composite(re.path);
- auto dst_ty = ::HIR::TypeRef(&data_ty);
- new_val = Value(dst_ty);
- LOG_DEBUG("Variant " << new_val);
- // Three cases:
- // - Unions (no tag)
- // - Data enums (tag and data)
- // - Value enums (no data)
- const auto& var = data_ty.variants.at(re.index);
- if( var.data_field != SIZE_MAX )
- {
- const auto& fld = data_ty.fields.at(re.index);
-
- new_val.write_value(fld.first, state.param_to_value(re.val));
- }
- LOG_DEBUG("Variant " << new_val);
- if( var.base_field != SIZE_MAX )
- {
- ::HIR::TypeRef tag_ty;
- size_t tag_ofs = dst_ty.get_field_ofs(var.base_field, var.field_path, tag_ty);
- LOG_ASSERT(tag_ty.get_size() == var.tag_data.size(), "");
- new_val.write_bytes(tag_ofs, var.tag_data.data(), var.tag_data.size());
- }
- else
- {
- // Union, no tag
- }
- LOG_DEBUG("Variant " << new_val);
- } break;
- TU_ARM(se.src, Struct, re) {
- const auto& data_ty = state.modtree.get_composite(re.path);
-
- ::HIR::TypeRef dst_ty;
- state.get_value_and_type(se.dst, dst_ty);
- new_val = Value(dst_ty);
- LOG_ASSERT(dst_ty.composite_type == &data_ty, "Destination type of RValue::Struct isn't the same as the input");
-
- for(size_t i = 0; i < re.vals.size(); i++)
- {
- auto fld_ofs = data_ty.fields.at(i).first;
- new_val.write_value(fld_ofs, state.param_to_value(re.vals[i]));
- }
- } break;
- }
- LOG_DEBUG("- " << new_val);
- state.write_lvalue(se.dst, ::std::move(new_val));
- } break;
- case ::MIR::Statement::TAG_Asm:
- LOG_TODO(stmt);
- break;
- TU_ARM(stmt, Drop, se) {
- if( se.flag_idx == ~0u || state.drop_flags.at(se.flag_idx) )
- {
- ::HIR::TypeRef ty;
- auto v = state.get_value_and_type(se.slot, ty);
-
- // - Take a pointer to the inner
- auto alloc = v.m_alloc;
- if( !alloc )
- {
- if( !v.m_value->allocation )
- {
- v.m_value->create_allocation();
- }
- alloc = AllocationPtr(v.m_value->allocation);
- }
- size_t ofs = v.m_offset;
- assert(!ty.get_meta_type());
-
- auto ptr_ty = ty.wrap(TypeWrapper::Ty::Borrow, 2);
-
- auto ptr_val = Value(ptr_ty);
- ptr_val.write_usize(0, ofs);
- ptr_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) });
-
- drop_value(modtree, ptr_val, ty);
- // TODO: Clear validity on the entire inner value.
- //alloc.mark_as_freed();
- }
- } break;
- TU_ARM(stmt, SetDropFlag, se) {
- bool val = (se.other == ~0 ? false : state.drop_flags.at(se.other)) != se.new_val;
- LOG_DEBUG("- " << val);
- state.drop_flags.at(se.idx) = val;
- } break;
- case ::MIR::Statement::TAG_ScopeEnd:
- LOG_TODO(stmt);
- break;
- }
- }
-
- LOG_DEBUG("BB" << bb_idx << "/TERM: " << bb.terminator);
- switch(bb.terminator.tag())
- {
- case ::MIR::Terminator::TAGDEAD: throw "";
- TU_ARM(bb.terminator, Incomplete, _te)
- LOG_TODO("Terminator::Incomplete hit");
- TU_ARM(bb.terminator, Diverge, _te)
- LOG_TODO("Terminator::Diverge hit");
- TU_ARM(bb.terminator, Panic, _te)
- LOG_TODO("Terminator::Panic");
- TU_ARM(bb.terminator, Goto, te)
- bb_idx = te;
- continue;
- TU_ARM(bb.terminator, Return, _te)
- LOG_DEBUG("RETURN " << state.ret);
- return state.ret;
- TU_ARM(bb.terminator, If, te) {
- uint8_t v = state.get_value_ref(te.cond).read_u8(0);
- LOG_ASSERT(v == 0 || v == 1, "");
- bb_idx = v ? te.bb0 : te.bb1;
- } continue;
- TU_ARM(bb.terminator, Switch, te) {
- ::HIR::TypeRef ty;
- auto v = state.get_value_and_type(te.val, ty);
- LOG_ASSERT(ty.wrappers.size() == 0, "" << ty);
- LOG_ASSERT(ty.inner_type == RawType::Composite, "" << ty);
-
- // TODO: Convert the variant list into something that makes it easier to switch on.
- size_t found_target = SIZE_MAX;
- size_t default_target = SIZE_MAX;
- for(size_t i = 0; i < ty.composite_type->variants.size(); i ++)
- {
- const auto& var = ty.composite_type->variants[i];
- if( var.tag_data.size() == 0 )
- {
- // Save as the default, error for multiple defaults
- if( default_target != SIZE_MAX )
- {
- LOG_FATAL("Two variants with no tag in Switch");
- }
- default_target = i;
- }
- else
- {
- // Get offset, read the value.
- ::HIR::TypeRef tag_ty;
- size_t tag_ofs = ty.get_field_ofs(var.base_field, var.field_path, tag_ty);
- // Read the value bytes
- ::std::vector<char> tmp( var.tag_data.size() );
- v.read_bytes(tag_ofs, const_cast<char*>(tmp.data()), tmp.size());
- if( v.get_relocation(tag_ofs) )
- continue ;
- if( ::std::memcmp(tmp.data(), var.tag_data.data(), tmp.size()) == 0 )
- {
- found_target = i;
- break ;
- }
- }
- }
-
- if( found_target == SIZE_MAX )
- {
- found_target = default_target;
- }
- if( found_target == SIZE_MAX )
- {
- LOG_FATAL("Terminator::Switch on " << ty << " didn't find a variant");
- }
- bb_idx = te.targets.at(found_target);
- } continue;
- TU_ARM(bb.terminator, SwitchValue, _te)
- LOG_TODO("Terminator::SwitchValue");
- TU_ARM(bb.terminator, Call, te) {
- ::std::vector<Value> sub_args; sub_args.reserve(te.args.size());
- for(const auto& a : te.args)
- {
- sub_args.push_back( state.param_to_value(a) );
- }
- if( te.fcn.is_Intrinsic() )
- {
- const auto& fe = te.fcn.as_Intrinsic();
- state.write_lvalue(te.ret_val, MIRI_Invoke_Intrinsic(modtree, fe.name, fe.params, ::std::move(sub_args)));
- }
- else
- {
- const ::HIR::Path* fcn_p;
- if( te.fcn.is_Path() ) {
- fcn_p = &te.fcn.as_Path();
- }
- else {
- ::HIR::TypeRef ty;
- auto v = state.get_value_and_type(te.fcn.as_Value(), ty);
- // TODO: Assert type
- // TODO: Assert offset/content.
- assert(v.read_usize(v.m_offset) == 0);
- auto& alloc_ptr = v.m_alloc ? v.m_alloc : v.m_value->allocation;
- LOG_ASSERT(alloc_ptr, "Calling value that can't be a pointer (no allocation)");
- auto& fcn_alloc_ptr = alloc_ptr.alloc().get_relocation(v.m_offset);
- LOG_ASSERT(fcn_alloc_ptr, "Calling value with no relocation");
- LOG_ASSERT(fcn_alloc_ptr.get_ty() == AllocationPtr::Ty::Function, "Calling value that isn't a function pointer");
- fcn_p = &fcn_alloc_ptr.fcn();
- }
-
- LOG_DEBUG("Call " << *fcn_p);
- auto v = MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args));
- LOG_DEBUG(te.ret_val << " = " << v << " (resume " << path << ")");
- state.write_lvalue(te.ret_val, ::std::move(v));
- }
- bb_idx = te.ret_block;
- } continue;
- }
- throw "";
- }
-
- throw "";
-}
-Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& abi, ::std::vector<Value> args)
-{
- if( link_name == "__rust_allocate" )
- {
- auto size = args.at(0).read_usize(0);
- auto align = args.at(1).read_usize(0);
- LOG_DEBUG("__rust_allocate(size=" << size << ", align=" << align << ")");
- ::HIR::TypeRef rty { RawType::Unit };
- rty.wrappers.push_back({ TypeWrapper::Ty::Pointer, 0 });
- Value rv = Value(rty);
- rv.write_usize(0, 0);
- // TODO: Use the alignment when making an allocation?
- rv.allocation.alloc().relocations.push_back({ 0, Allocation::new_alloc(size) });
- return rv;
- }
- else if( link_name == "__rust_reallocate" )
- {
- LOG_ASSERT(args.at(0).allocation, "__rust_reallocate first argument doesn't have an allocation");
- auto alloc_ptr = args.at(0).allocation.alloc().get_relocation(0);
- auto ptr_ofs = args.at(0).read_usize(0);
- LOG_ASSERT(ptr_ofs == 0, "__rust_reallocate with offset pointer");
- auto oldsize = args.at(1).read_usize(0);
- auto newsize = args.at(2).read_usize(0);
- auto align = args.at(3).read_usize(0);
- LOG_DEBUG("__rust_reallocate(ptr=" << alloc_ptr << ", oldsize=" << oldsize << ", newsize=" << newsize << ", align=" << align << ")");
-
- LOG_ASSERT(alloc_ptr, "__rust_reallocate with no backing allocation attached to pointer");
- LOG_ASSERT(alloc_ptr.is_alloc(), "__rust_reallocate with no backing allocation attached to pointer");
- auto& alloc = alloc_ptr.alloc();
- // TODO: Check old size and alignment against allocation.
- alloc.data.resize( (newsize + 8-1) / 8 );
- alloc.mask.resize( (newsize + 8-1) / 8 );
- // TODO: Should this instead make a new allocation to catch use-after-free?
- return ::std::move(args.at(0));
- }
- else if( link_name == "__rust_deallocate" )
- {
- LOG_ASSERT(args.at(0).allocation, "__rust_deallocate first argument doesn't have an allocation");
- auto alloc_ptr = args.at(0).allocation.alloc().get_relocation(0);
- auto ptr_ofs = args.at(0).read_usize(0);
- LOG_ASSERT(ptr_ofs == 0, "__rust_deallocate with offset pointer");
-
- LOG_ASSERT(alloc_ptr, "__rust_deallocate with no backing allocation attached to pointer");
- LOG_ASSERT(alloc_ptr.is_alloc(), "__rust_deallocate with no backing allocation attached to pointer");
- auto& alloc = alloc_ptr.alloc();
- // TODO: Figure out how to prevent this ever being written again.
- //alloc.mark_as_freed();
- for(auto& v : alloc.mask)
- v = 0;
- // Just let it drop.
- return Value();
- }
-#ifdef _WIN32
- // WinAPI functions used by libstd
- else if( link_name == "AddVectoredExceptionHandler" )
- {
- LOG_DEBUG("Call `AddVectoredExceptionHandler` - Ignoring and returning non-null");
- auto rv = Value(::HIR::TypeRef(RawType::USize));
- rv.write_usize(0, 1);
- return rv;
- }
- else if( link_name == "GetModuleHandleW" )
- {
- LOG_ASSERT(args.at(0).allocation.is_alloc(), "");
- const auto& tgt_alloc = args.at(0).allocation.alloc().get_relocation(0);
- const void* arg0 = (tgt_alloc ? tgt_alloc.alloc().data_ptr() : nullptr);
- //extern void* GetModuleHandleW(const void* s);
- if(arg0) {
- LOG_DEBUG("GetModuleHandleW(" << tgt_alloc.alloc() << ")");
- }
- else {
- LOG_DEBUG("GetModuleHandleW(NULL)");
- }
-
- auto rv = GetModuleHandleW(static_cast<LPCWSTR>(arg0));
- if(rv)
- {
- return Value::new_ffiptr(FFIPointer { "GetModuleHandleW", rv });
- }
- else
- {
- auto rv = Value(::HIR::TypeRef(RawType::USize));
- rv.create_allocation();
- rv.write_usize(0,0);
- return rv;
- }
- }
- else if( link_name == "GetProcAddress" )
- {
- LOG_ASSERT(args.at(0).allocation.is_alloc(), "");
- const auto& handle_alloc = args.at(0).allocation.alloc().get_relocation(0);
- LOG_ASSERT(args.at(1).allocation.is_alloc(), "");
- const auto& sym_alloc = args.at(1).allocation.alloc().get_relocation(0);
-
- // TODO: Ensure that first arg is a FFI pointer with offset+size of zero
- void* handle = handle_alloc.ffi().ptr_value;
- // TODO: Get either a FFI data pointer, or a inner data pointer
- const void* symname = sym_alloc.alloc().data_ptr();
- // TODO: Sanity check that it's a valid c string within its allocation
- LOG_DEBUG("FFI GetProcAddress(" << handle << ", \"" << static_cast<const char*>(symname) << "\")");
-
- auto rv = GetProcAddress(static_cast<HMODULE>(handle), static_cast<LPCSTR>(symname));
-
- if( rv )
- {
- return Value::new_ffiptr(FFIPointer { "GetProcAddress", rv });
- }
- else
+ args.push_back(::std::move(val_argc));
+ args.push_back(::std::move(val_argv));
+ Value rv;
+ root_thread.start(tree.find_lang_item("start"), ::std::move(args));
+ while( !root_thread.step_one(rv) )
{
- auto rv = Value(::HIR::TypeRef(RawType::USize));
- rv.create_allocation();
- rv.write_usize(0,0);
- return rv;
- }
- }
-#endif
- // Allocators!
- else
- {
- LOG_TODO("Call external function " << link_name);
- }
- throw "";
-}
-Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector<Value> args)
-{
- Value rv;
- TRACE_FUNCTION_R(name, rv);
- for(const auto& a : args)
- LOG_DEBUG("#" << (&a - args.data()) << ": " << a);
- if( name == "atomic_store" )
- {
- auto& ptr_val = args.at(0);
- auto& data_val = args.at(1);
-
- LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_store of a value that isn't a pointer-sized value");
-
- // There MUST be a relocation at this point with a valid allocation.
- LOG_ASSERT(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)");
- LOG_TRACE("Deref " << ptr_val.allocation.alloc());
- auto alloc = ptr_val.allocation.alloc().get_relocation(0);
- LOG_ASSERT(alloc, "Deref of a value with no relocation");
-
- // TODO: Atomic side of this?
- size_t ofs = ptr_val.read_usize(0);
- const auto& ty = ty_params.tys.at(0);
- alloc.alloc().write_value(ofs, ::std::move(data_val));
- }
- else if( name == "atomic_load" )
- {
- auto& ptr_val = args.at(0);
- LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_store of a value that isn't a pointer-sized value");
-
- // There MUST be a relocation at this point with a valid allocation.
- LOG_ASSERT(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)");
- LOG_TRACE("Deref " << ptr_val.allocation.alloc());
- auto alloc = ptr_val.allocation.alloc().get_relocation(0);
- LOG_ASSERT(alloc, "Deref of a value with no relocation");
-
- // TODO: Atomic side of this?
- size_t ofs = ptr_val.read_usize(0);
- const auto& ty = ty_params.tys.at(0);
- rv = alloc.alloc().read_value(ofs, ty.get_size());
- }
- else if( name == "transmute" )
- {
- // Transmute requires the same size, so just copying the value works
- rv = ::std::move(args.at(0));
- }
- else if( name == "assume" )
- {
- // Assume is a no-op which returns unit
- }
- else if( name == "offset" )
- {
- auto ptr_val = ::std::move(args.at(0));
- auto& ofs_val = args.at(1);
-
- auto r = ptr_val.allocation.alloc().get_relocation(0);
- auto orig_ofs = ptr_val.read_usize(0);
- auto delta_counts = ofs_val.read_usize(0);
- auto new_ofs = orig_ofs + delta_counts * ty_params.tys.at(0).get_size();
- if(POINTER_SIZE != 8) {
- new_ofs &= 0xFFFFFFFF;
}
- ptr_val.write_usize(0, new_ofs);
- ptr_val.allocation.alloc().relocations.push_back({ 0, r });
- rv = ::std::move(ptr_val);
- }
- // effectively ptr::write
- else if( name == "move_val_init" )
- {
- auto& ptr_val = args.at(0);
- auto& data_val = args.at(1);
-
- LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "move_val_init of an address that isn't a pointer-sized value");
-
- // There MUST be a relocation at this point with a valid allocation.
- LOG_ASSERT(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)");
- LOG_TRACE("Deref " << ptr_val << " and store " << data_val);
- auto alloc = ptr_val.allocation.alloc().get_relocation(0);
- LOG_ASSERT(alloc, "Deref of a value with no relocation");
-
- size_t ofs = ptr_val.read_usize(0);
- const auto& ty = ty_params.tys.at(0);
- alloc.alloc().write_value(ofs, ::std::move(data_val));
- LOG_DEBUG(alloc.alloc());
- }
- else if( name == "uninit" )
- {
- rv = Value(ty_params.tys.at(0));
+ LOG_NOTICE("Return code: " << rv);
}
- // - Unsized stuff
- else if( name == "size_of_val" )
+ catch(const DebugExceptionTodo& /*e*/)
{
- auto& val = args.at(0);
- const auto& ty = ty_params.tys.at(0);
- rv = Value(::HIR::TypeRef(RawType::USize));
- // Get unsized type somehow.
- // - _HAS_ to be the last type, so that makes it easier
- size_t fixed_size = 0;
- if( const auto* ity = ty.get_usized_type(fixed_size) )
- {
- const auto& meta_ty = *ty.get_meta_type();
- LOG_DEBUG("size_of_val - " << ty << " ity=" << *ity << " meta_ty=" << meta_ty << " fixed_size=" << fixed_size);
- size_t flex_size = 0;
- if( !ity->wrappers.empty() )
- {
- LOG_ASSERT(ity->wrappers[0].type == TypeWrapper::Ty::Slice, "");
- size_t item_size = ity->get_inner().get_size();
- size_t item_count = val.read_usize(POINTER_SIZE);
- flex_size = item_count * item_size;
- LOG_DEBUG("> item_size=" << item_size << " item_count=" << item_count << " flex_size=" << flex_size);
- }
- else if( ity->inner_type == RawType::Str )
- {
- flex_size = val.read_usize(POINTER_SIZE);
- }
- else if( ity->inner_type == RawType::TraitObject )
- {
- LOG_TODO("size_of_val - Trait Object - " << ty);
- }
- else
- {
- LOG_BUG("Inner unsized type unknown - " << *ity);
- }
-
- rv.write_usize(0, fixed_size + flex_size);
- }
- else
+ ::std::cerr << "TODO Hit" << ::std::endl;
+ if(opts.logfile != "")
{
- rv.write_usize(0, ty.get_size());
+ ::std::cerr << "- See '" << opts.logfile << "' for details" << ::std::endl;
}
+ return 1;
}
- else if( name == "drop_in_place" )
+ catch(const DebugExceptionError& /*e*/)
{
- auto& val = args.at(0);
- const auto& ty = ty_params.tys.at(0);
- if( !ty.wrappers.empty() )
- {
- size_t item_count = 0;
- switch(ty.wrappers[0].type)
- {
- case TypeWrapper::Ty::Slice:
- case TypeWrapper::Ty::Array:
- item_count = (ty.wrappers[0].type == TypeWrapper::Ty::Slice ? val.read_usize(POINTER_SIZE) : ty.wrappers[0].size);
- break;
- case TypeWrapper::Ty::Pointer:
- break;
- case TypeWrapper::Ty::Borrow:
- break;
- }
- LOG_ASSERT(ty.wrappers[0].type == TypeWrapper::Ty::Slice, "drop_in_place should only exist for slices - " << ty);
- const auto& ity = ty.get_inner();
- size_t item_size = ity.get_size();
-
- auto ptr = val.read_value(0, POINTER_SIZE);;
- for(size_t i = 0; i < item_count; i ++)
- {
- drop_value(modtree, ptr, ity);
- ptr.write_usize(0, ptr.read_usize(0) + item_size);
- }
- }
- else
+ ::std::cerr << "Error encountered" << ::std::endl;
+ if(opts.logfile != "")
{
- LOG_TODO("drop_in_place - " << ty);
+ ::std::cerr << "- See '" << opts.logfile << "' for details" << ::std::endl;
}
+ return 1;
}
- // ----------------------------------------------------------------
- // Checked arithmatic
- else if( name == "add_with_overflow" )
- {
- const auto& ty = ty_params.tys.at(0);
-
- auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
- auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
- bool didnt_overflow = lhs.get().add( rhs.get() );
-
- // Get return type - a tuple of `(T, bool,)`
- ::HIR::GenericPath gp;
- gp.m_params.tys.push_back(ty);
- gp.m_params.tys.push_back(::HIR::TypeRef { RawType::Bool });
- const auto& dty = modtree.get_composite(gp);
-
- rv = Value(::HIR::TypeRef(&dty));
- lhs.get().write_to_value(rv, dty.fields[0].first);
- rv.write_u8( dty.fields[1].first, didnt_overflow ? 0 : 1 ); // Returns true if overflow happened
- }
- else if( name == "sub_with_overflow" )
- {
- const auto& ty = ty_params.tys.at(0);
-
- auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
- auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
- bool didnt_overflow = lhs.get().subtract( rhs.get() );
-
- // Get return type - a tuple of `(T, bool,)`
- ::HIR::GenericPath gp;
- gp.m_params.tys.push_back(ty);
- gp.m_params.tys.push_back(::HIR::TypeRef { RawType::Bool });
- const auto& dty = modtree.get_composite(gp);
-
- rv = Value(::HIR::TypeRef(&dty));
- lhs.get().write_to_value(rv, dty.fields[0].first);
- rv.write_u8( dty.fields[1].first, didnt_overflow ? 0 : 1 ); // Returns true if overflow happened
- }
- else if( name == "mul_with_overflow" )
- {
- const auto& ty = ty_params.tys.at(0);
-
- auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
- auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
- bool didnt_overflow = lhs.get().multiply( rhs.get() );
-
- // Get return type - a tuple of `(T, bool,)`
- ::HIR::GenericPath gp;
- gp.m_params.tys.push_back(ty);
- gp.m_params.tys.push_back(::HIR::TypeRef { RawType::Bool });
- const auto& dty = modtree.get_composite(gp);
-
- rv = Value(::HIR::TypeRef(&dty));
- lhs.get().write_to_value(rv, dty.fields[0].first);
- rv.write_u8( dty.fields[1].first, didnt_overflow ? 0 : 1 ); // Returns true if overflow happened
- }
- // Overflowing artithmatic
- else if( name == "overflowing_sub" )
- {
- const auto& ty = ty_params.tys.at(0);
-
- auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
- auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
- lhs.get().subtract( rhs.get() );
-
- rv = Value(ty);
- lhs.get().write_to_value(rv, 0);
- }
- // ----------------------------------------------------------------
- // memcpy
- else if( name == "copy_nonoverlapping" )
- {
- auto src_ofs = args.at(0).read_usize(0);
- auto src_alloc = args.at(0).allocation.alloc().get_relocation(0);
- auto dst_ofs = args.at(1).read_usize(0);
- auto dst_alloc = args.at(1).allocation.alloc().get_relocation(0);
- size_t ent_count = args.at(2).read_usize(0);
- size_t ent_size = ty_params.tys.at(0).get_size();
- auto byte_count = ent_count * ent_size;
-
- LOG_ASSERT(src_alloc, "Source of copy* must have an allocation");
- LOG_ASSERT(dst_alloc, "Destination of copy* must be a memory allocation");
- LOG_ASSERT(dst_alloc.is_alloc(), "Destination of copy* must be a memory allocation");
- switch(src_alloc.get_ty())
- {
- case AllocationPtr::Ty::Allocation: {
- auto v = src_alloc.alloc().read_value(src_ofs, byte_count);
- dst_alloc.alloc().write_value(dst_ofs, ::std::move(v));
- } break;
- case AllocationPtr::Ty::StdString:
- LOG_ASSERT(src_ofs <= src_alloc.str().size(), "");
- LOG_ASSERT(byte_count <= src_alloc.str().size(), "");
- LOG_ASSERT(src_ofs + byte_count <= src_alloc.str().size(), "");
- dst_alloc.alloc().write_bytes(dst_ofs, src_alloc.str().data() + src_ofs, byte_count);
- break;
- case AllocationPtr::Ty::Function:
- LOG_FATAL("Attempt to copy* a function");
- break;
- case AllocationPtr::Ty::FfiPointer:
- LOG_BUG("Trying to copy from a FFI pointer");
- break;
- }
- }
- else
- {
- LOG_TODO("Call intrinsic \"" << name << "\"");
- }
- return rv;
+ return 0;
}
int ProgramOptions::parse(int argc, const char* argv[])
{
bool all_free = false;
+ // TODO: use getopt? POSIX only
for(int argidx = 1; argidx < argc; argidx ++)
{
const char* arg = argv[argidx];
if( arg[0] != '-' || all_free )
{
- // Free
+ // Free arguments
+ // - First is the input file
if( this->infile == "" )
{
this->infile = arg;
}
else
{
- // TODO: Too many free arguments
+ // Any subsequent arguments are passed to the taget
+ this->args.push_back(arg);
}
}
else if( arg[1] != '-' )
{
- // Short
+ // Short arguments
+ if( arg[2] != '\0' ) {
+ // Error?
+ ::std::cerr << "Unexpected option " << arg << ::std::endl;
+ return 1;
+ }
+ switch(arg[1])
+ {
+ case 'h':
+ this->show_help(argv[0]);
+ exit(0);
+ default:
+ ::std::cerr << "Unexpected option -" << arg[1] << ::std::endl;
+ return 1;
+ }
}
else if( arg[2] != '\0' )
{
// Long
+ if( ::std::strcmp(arg, "--help") == 0 ) {
+ this->show_help(argv[0]);
+ exit(0);
+ }
+ else if( ::std::strcmp(arg, "--logfile") == 0 ) {
+ if( argidx + 1 == argc ) {
+ ::std::cerr << "Option " << arg << " requires an argument" << ::std::endl;
+ return 1;
+ }
+ const char* opt = argv[++argidx];
+ this->logfile = opt;
+ }
+ //else if( ::std::strcmp(arg, "--api") == 0 ) {
+ //}
+ else {
+ ::std::cerr << "Unexpected option " << arg << ::std::endl;
+ return 1;
+ }
}
else
{
@@ -1948,3 +192,8 @@ int ProgramOptions::parse(int argc, const char* argv[])
}
return 0;
}
+
+void ProgramOptions::show_help(const char* prog) const
+{
+ ::std::cout << "USAGE: " << prog << " <infile> <... args>" << ::std::endl;
+}
diff --git a/tools/standalone_miri/mir.cpp b/tools/standalone_miri/mir.cpp
index 4593fb44..a0601823 100644
--- a/tools/standalone_miri/mir.cpp
+++ b/tools/standalone_miri/mir.cpp
@@ -7,6 +7,7 @@
*/
#include "../../src/mir/mir.hpp"
#include "hir_sim.hpp"
+#include <iostream>
namespace std {
template <typename T>
diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp
new file mode 100644
index 00000000..f4179b5d
--- /dev/null
+++ b/tools/standalone_miri/miri.cpp
@@ -0,0 +1,2305 @@
+/*
+ * mrustc Standalone MIRI
+ * - by John Hodge (Mutabah)
+ *
+ * miri.cpp
+ * - Interpreter core
+ */
+#include <iostream>
+#include "module_tree.hpp"
+#include "value.hpp"
+#include <algorithm>
+#include <iomanip>
+#include "debug.hpp"
+#include "miri.hpp"
+#ifdef _WIN32
+# define NOMINMAX
+# include <Windows.h>
+#endif
+
+unsigned ThreadState::s_next_tls_key = 1;
+
+class PrimitiveValue
+{
+public:
+ virtual ~PrimitiveValue() {}
+
+ virtual bool add(const PrimitiveValue& v) = 0;
+ virtual bool subtract(const PrimitiveValue& v) = 0;
+ virtual bool multiply(const PrimitiveValue& v) = 0;
+ virtual bool divide(const PrimitiveValue& v) = 0;
+ virtual bool modulo(const PrimitiveValue& v) = 0;
+ virtual void write_to_value(ValueCommonWrite& tgt, size_t ofs) const = 0;
+
+ template<typename T>
+ const T& check(const char* opname) const
+ {
+ const auto* xp = dynamic_cast<const T*>(this);
+ LOG_ASSERT(xp, "Attempting to " << opname << " mismatched types, expected " << typeid(T).name() << " got " << typeid(*this).name());
+ return *xp;
+ }
+};
+template<typename T>
+struct PrimitiveUInt:
+ public PrimitiveValue
+{
+ typedef PrimitiveUInt<T> Self;
+ T v;
+
+ PrimitiveUInt(T v): v(v) {}
+ ~PrimitiveUInt() override {}
+
+ bool add(const PrimitiveValue& x) override {
+ const auto* xp = &x.check<Self>("add");
+ T newv = this->v + xp->v;
+ bool did_overflow = newv < this->v;
+ this->v = newv;
+ return !did_overflow;
+ }
+ bool subtract(const PrimitiveValue& x) override {
+ const auto* xp = &x.check<Self>("subtract");
+ T newv = this->v - xp->v;
+ bool did_overflow = newv > this->v;
+ this->v = newv;
+ return !did_overflow;
+ }
+ bool multiply(const PrimitiveValue& x) override {
+ const auto* xp = &x.check<Self>("multiply");
+ T newv = this->v * xp->v;
+ bool did_overflow = newv < this->v && newv < xp->v;
+ this->v = newv;
+ return !did_overflow;
+ }
+ bool divide(const PrimitiveValue& x) override {
+ const auto* xp = &x.check<Self>("divide");
+ if(xp->v == 0) return false;
+ T newv = this->v / xp->v;
+ this->v = newv;
+ return true;
+ }
+ bool modulo(const PrimitiveValue& x) override {
+ const auto* xp = &x.check<Self>("modulo");
+ if(xp->v == 0) return false;
+ T newv = this->v % xp->v;
+ this->v = newv;
+ return true;
+ }
+};
+struct PrimitiveU64: public PrimitiveUInt<uint64_t>
+{
+ PrimitiveU64(uint64_t v): PrimitiveUInt(v) {}
+ void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override {
+ tgt.write_u64(ofs, this->v);
+ }
+};
+struct PrimitiveU32: public PrimitiveUInt<uint32_t>
+{
+ PrimitiveU32(uint32_t v): PrimitiveUInt(v) {}
+ void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override {
+ tgt.write_u32(ofs, this->v);
+ }
+};
+template<typename T>
+struct PrimitiveSInt:
+ public PrimitiveValue
+{
+ typedef PrimitiveSInt<T> Self;
+ T v;
+
+ PrimitiveSInt(T v): v(v) {}
+ ~PrimitiveSInt() override {}
+
+ // TODO: Make this correct.
+ bool add(const PrimitiveValue& x) override {
+ const auto* xp = &x.check<Self>("add");
+ T newv = this->v + xp->v;
+ bool did_overflow = newv < this->v;
+ this->v = newv;
+ return !did_overflow;
+ }
+ bool subtract(const PrimitiveValue& x) override {
+ const auto* xp = &x.check<Self>("subtract");
+ T newv = this->v - xp->v;
+ bool did_overflow = newv > this->v;
+ this->v = newv;
+ return !did_overflow;
+ }
+ bool multiply(const PrimitiveValue& x) override {
+ const auto* xp = &x.check<Self>("multiply");
+ T newv = this->v * xp->v;
+ bool did_overflow = newv < this->v && newv < xp->v;
+ this->v = newv;
+ return !did_overflow;
+ }
+ bool divide(const PrimitiveValue& x) override {
+ const auto* xp = &x.check<Self>("divide");
+ if(xp->v == 0) return false;
+ T newv = this->v / xp->v;
+ this->v = newv;
+ return true;
+ }
+ bool modulo(const PrimitiveValue& x) override {
+ const auto* xp = &x.check<Self>("modulo");
+ if(xp->v == 0) return false;
+ T newv = this->v % xp->v;
+ this->v = newv;
+ return true;
+ }
+};
+struct PrimitiveI64: public PrimitiveSInt<int64_t>
+{
+ PrimitiveI64(int64_t v): PrimitiveSInt(v) {}
+ void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override {
+ tgt.write_i64(ofs, this->v);
+ }
+};
+struct PrimitiveI32: public PrimitiveSInt<int32_t>
+{
+ PrimitiveI32(int32_t v): PrimitiveSInt(v) {}
+ void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override {
+ tgt.write_i32(ofs, this->v);
+ }
+};
+
+class PrimitiveValueVirt
+{
+ uint64_t buf[3]; // Allows i128 plus a vtable pointer
+ PrimitiveValueVirt() {}
+public:
+ // HACK: No copy/move constructors, assumes that contained data is always POD
+ ~PrimitiveValueVirt() {
+ reinterpret_cast<PrimitiveValue*>(&this->buf)->~PrimitiveValue();
+ }
+ PrimitiveValue& get() { return *reinterpret_cast<PrimitiveValue*>(&this->buf); }
+ const PrimitiveValue& get() const { return *reinterpret_cast<const PrimitiveValue*>(&this->buf); }
+
+ static PrimitiveValueVirt from_value(const ::HIR::TypeRef& t, const ValueRef& v) {
+ PrimitiveValueVirt rv;
+ LOG_ASSERT(t.get_wrapper() == nullptr, "PrimitiveValueVirt::from_value: " << t);
+ switch(t.inner_type)
+ {
+ case RawType::U32:
+ new(&rv.buf) PrimitiveU32(v.read_u32(0));
+ break;
+ case RawType::U64:
+ new(&rv.buf) PrimitiveU64(v.read_u64(0));
+ break;
+ case RawType::USize:
+ if( POINTER_SIZE == 8 )
+ new(&rv.buf) PrimitiveU64(v.read_u64(0));
+ else
+ new(&rv.buf) PrimitiveU32(v.read_u32(0));
+ break;
+
+ case RawType::I32:
+ new(&rv.buf) PrimitiveI32(v.read_i32(0));
+ break;
+ case RawType::I64:
+ new(&rv.buf) PrimitiveI64(v.read_i64(0));
+ break;
+ case RawType::ISize:
+ if( POINTER_SIZE == 8 )
+ new(&rv.buf) PrimitiveI64(v.read_i64(0));
+ else
+ new(&rv.buf) PrimitiveI32(v.read_i32(0));
+ break;
+ default:
+ LOG_TODO("PrimitiveValueVirt::from_value: " << t);
+ }
+ return rv;
+ }
+};
+
+struct Ops {
+ template<typename T>
+ static int do_compare(T l, T r) {
+ if( l == r ) {
+ return 0;
+ }
+ else if( !(l != r) ) {
+ // Special return value for NaN w/ NaN
+ return 2;
+ }
+ else if( l < r ) {
+ return -1;
+ }
+ else {
+ return 1;
+ }
+ }
+ template<typename T>
+ static T do_bitwise(T l, T r, ::MIR::eBinOp op) {
+ switch(op)
+ {
+ case ::MIR::eBinOp::BIT_AND: return l & r;
+ case ::MIR::eBinOp::BIT_OR: return l | r;
+ case ::MIR::eBinOp::BIT_XOR: return l ^ r;
+ case ::MIR::eBinOp::BIT_SHL: return l << r;
+ case ::MIR::eBinOp::BIT_SHR: return l >> r;
+ default:
+ LOG_BUG("Unexpected operation in Ops::do_bitwise");
+ }
+ }
+};
+
+struct MirHelpers
+{
+ InterpreterThread& thread;
+ InterpreterThread::StackFrame& frame;
+
+ MirHelpers(InterpreterThread& thread, InterpreterThread::StackFrame& frame):
+ thread(thread),
+ frame(frame)
+ {
+ }
+
+ ValueRef get_value_and_type(const ::MIR::LValue& lv, ::HIR::TypeRef& ty)
+ {
+ switch(lv.tag())
+ {
+ case ::MIR::LValue::TAGDEAD: throw "";
+ // --> Slots
+ TU_ARM(lv, Return, _e) {
+ ty = this->frame.fcn.ret_ty;
+ return ValueRef(this->frame.ret);
+ } break;
+ TU_ARM(lv, Local, e) {
+ ty = this->frame.fcn.m_mir.locals.at(e);
+ return ValueRef(this->frame.locals.at(e));
+ } break;
+ TU_ARM(lv, Argument, e) {
+ ty = this->frame.fcn.args.at(e.idx);
+ return ValueRef(this->frame.args.at(e.idx));
+ } break;
+ TU_ARM(lv, Static, e) {
+ /*const*/ auto& s = this->thread.m_modtree.get_static(e);
+ ty = s.ty;
+ return ValueRef(s.val);
+ } break;
+ // --> Modifiers
+ TU_ARM(lv, Index, e) {
+ auto idx = get_value_ref(*e.idx).read_usize(0);
+ ::HIR::TypeRef array_ty;
+ auto base_val = get_value_and_type(*e.val, array_ty);
+ const auto* wrapper = array_ty.get_wrapper();
+ if( !wrapper )
+ {
+ LOG_ERROR("Indexing non-array/slice - " << array_ty);
+ }
+ else if( wrapper->type == TypeWrapper::Ty::Array )
+ {
+ ty = array_ty.get_inner();
+ base_val.m_offset += ty.get_size() * idx;
+ return base_val;
+ }
+ else if( wrapper->type == TypeWrapper::Ty::Slice )
+ {
+ LOG_TODO("Slice index");
+ }
+ else
+ {
+ LOG_ERROR("Indexing non-array/slice - " << array_ty);
+ throw "ERROR";
+ }
+ } break;
+ TU_ARM(lv, Field, e) {
+ ::HIR::TypeRef composite_ty;
+ auto base_val = get_value_and_type(*e.val, composite_ty);
+ // TODO: if there's metadata present in the base, but the inner doesn't have metadata, clear the metadata
+ size_t inner_ofs;
+ ty = composite_ty.get_field(e.field_index, inner_ofs);
+ LOG_DEBUG("Field - " << composite_ty << "#" << e.field_index << " = @" << inner_ofs << " " << ty);
+ base_val.m_offset += inner_ofs;
+ if( ty.get_meta_type() == HIR::TypeRef(RawType::Unreachable) )
+ {
+ LOG_ASSERT(base_val.m_size >= ty.get_size(), "Field didn't fit in the value - " << ty.get_size() << " required, but " << base_val.m_size << " avail");
+ base_val.m_size = ty.get_size();
+ }
+ return base_val;
+ }
+ TU_ARM(lv, Downcast, e) {
+ ::HIR::TypeRef composite_ty;
+ auto base_val = get_value_and_type(*e.val, composite_ty);
+ LOG_DEBUG("Downcast - " << composite_ty);
+
+ size_t inner_ofs;
+ ty = composite_ty.get_field(e.variant_index, inner_ofs);
+ base_val.m_offset += inner_ofs;
+ return base_val;
+ }
+ TU_ARM(lv, Deref, e) {
+ ::HIR::TypeRef ptr_ty;
+ auto val = get_value_and_type(*e.val, ptr_ty);
+ ty = ptr_ty.get_inner();
+ LOG_DEBUG("val = " << val << ", (inner) ty=" << ty);
+
+ LOG_ASSERT(val.m_size >= POINTER_SIZE, "Deref of a value that doesn't fit a pointer - " << ty);
+ size_t ofs = val.read_usize(0);
+
+ // There MUST be a relocation at this point with a valid allocation.
+ auto alloc = val.get_relocation(val.m_offset);
+ LOG_TRACE("Deref " << alloc << " + " << ofs << " to give value of type " << ty);
+ // NOTE: No alloc can happen when dereferencing a zero-sized pointer
+ if( alloc.is_alloc() )
+ {
+ LOG_DEBUG("> " << lv << " alloc=" << alloc.alloc());
+ }
+ size_t size;
+
+ const auto meta_ty = ty.get_meta_type();
+ ::std::shared_ptr<Value> meta_val;
+ // If the type has metadata, store it.
+ if( meta_ty != RawType::Unreachable )
+ {
+ auto meta_size = meta_ty.get_size();
+ LOG_ASSERT(val.m_size == POINTER_SIZE + meta_size, "Deref of " << ty << ", but pointer isn't correct size");
+ meta_val = ::std::make_shared<Value>( val.read_value(POINTER_SIZE, meta_size) );
+
+ size_t slice_inner_size;
+ if( ty.has_slice_meta(slice_inner_size) ) {
+ size = (ty.get_wrapper() == nullptr ? ty.get_size() : 0) + meta_val->read_usize(0) * slice_inner_size;
+ }
+ //else if( ty == RawType::TraitObject) {
+ // // NOTE: Getting the size from the allocation is semi-valid, as you can't sub-slice trait objects
+ // size = alloc.get_size() - ofs;
+ //}
+ else {
+ LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs);
+ size = alloc.get_size() - ofs;
+ }
+ }
+ else
+ {
+ LOG_ASSERT(val.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value (size=" << val.m_size << ") - " << val << ": " << ptr_ty);
+ size = ty.get_size();
+ if( !alloc ) {
+ LOG_ERROR("Deref of a value with no relocation - " << val);
+ }
+ }
+
+ LOG_DEBUG("alloc=" << alloc << ", ofs=" << ofs << ", size=" << size);
+ auto rv = ValueRef(::std::move(alloc), ofs, size);
+ rv.m_metadata = ::std::move(meta_val);
+ return rv;
+ } break;
+ }
+ throw "";
+ }
+ ValueRef get_value_ref(const ::MIR::LValue& lv)
+ {
+ ::HIR::TypeRef tmp;
+ return get_value_and_type(lv, tmp);
+ }
+
+ ::HIR::TypeRef get_lvalue_ty(const ::MIR::LValue& lv)
+ {
+ ::HIR::TypeRef ty;
+ get_value_and_type(lv, ty);
+ return ty;
+ }
+
+ Value read_lvalue_with_ty(const ::MIR::LValue& lv, ::HIR::TypeRef& ty)
+ {
+ auto base_value = get_value_and_type(lv, ty);
+
+ return base_value.read_value(0, ty.get_size());
+ }
+ Value read_lvalue(const ::MIR::LValue& lv)
+ {
+ ::HIR::TypeRef ty;
+ return read_lvalue_with_ty(lv, ty);
+ }
+ void write_lvalue(const ::MIR::LValue& lv, Value val)
+ {
+ // TODO: Ensure that target is writable? Or should write_value do that?
+ //LOG_DEBUG(lv << " = " << val);
+ ::HIR::TypeRef ty;
+ auto base_value = get_value_and_type(lv, ty);
+
+ if(base_value.m_alloc) {
+ base_value.m_alloc.alloc().write_value(base_value.m_offset, ::std::move(val));
+ }
+ else {
+ base_value.m_value->write_value(base_value.m_offset, ::std::move(val));
+ }
+ }
+
+ Value const_to_value(const ::MIR::Constant& c, ::HIR::TypeRef& ty)
+ {
+ switch(c.tag())
+ {
+ case ::MIR::Constant::TAGDEAD: throw "";
+ TU_ARM(c, Int, ce) {
+ ty = ::HIR::TypeRef(ce.t);
+ Value val = Value(ty);
+ val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian
+ // TODO: If the write was clipped, sign-extend
+ // TODO: i128/u128 need the upper bytes cleared+valid
+ return val;
+ } break;
+ TU_ARM(c, Uint, ce) {
+ ty = ::HIR::TypeRef(ce.t);
+ Value val = Value(ty);
+ val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian
+ // TODO: i128/u128 need the upper bytes cleared+valid
+ return val;
+ } break;
+ TU_ARM(c, Bool, ce) {
+ Value val = Value(::HIR::TypeRef { RawType::Bool });
+ val.write_bytes(0, &ce.v, 1);
+ return val;
+ } break;
+ TU_ARM(c, Float, ce) {
+ ty = ::HIR::TypeRef(ce.t);
+ Value val = Value(ty);
+ if( ce.t.raw_type == RawType::F64 ) {
+ val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian/format?
+ }
+ else if( ce.t.raw_type == RawType::F32 ) {
+ float v = static_cast<float>(ce.v);
+ val.write_bytes(0, &v, ::std::min(ty.get_size(), sizeof(v))); // TODO: Endian/format?
+ }
+ else {
+ throw ::std::runtime_error("BUG: Invalid type in Constant::Float");
+ }
+ return val;
+ } break;
+ TU_ARM(c, Const, ce) {
+ LOG_BUG("Constant::Const in mmir");
+ } break;
+ TU_ARM(c, Bytes, ce) {
+ LOG_TODO("Constant::Bytes");
+ } break;
+ TU_ARM(c, StaticString, ce) {
+ ty = ::HIR::TypeRef(RawType::Str).wrap(TypeWrapper::Ty::Borrow, 0);
+ Value val = Value(ty);
+ val.write_ptr(0, 0, RelocationPtr::new_string(&ce));
+ val.write_usize(POINTER_SIZE, ce.size());
+ LOG_DEBUG(c << " = " << val);
+ return val;
+ } break;
+ // --> Accessor
+ TU_ARM(c, ItemAddr, ce) {
+ // Create a value with a special backing allocation of zero size that references the specified item.
+ if( /*const auto* fn =*/ this->thread.m_modtree.get_function_opt(ce) ) {
+ ty = ::HIR::TypeRef(RawType::Function);
+ return Value::new_fnptr(ce);
+ }
+ if( const auto* s = this->thread.m_modtree.get_static_opt(ce) ) {
+ ty = s->ty.wrapped(TypeWrapper::Ty::Borrow, 0);
+ return Value::new_pointer(ty, 0, RelocationPtr::new_alloc(s->val.allocation));
+ }
+ LOG_ERROR("Constant::ItemAddr - " << ce << " - not found");
+ } break;
+ }
+ throw "";
+ }
+ Value const_to_value(const ::MIR::Constant& c)
+ {
+ ::HIR::TypeRef ty;
+ return const_to_value(c, ty);
+ }
+ Value param_to_value(const ::MIR::Param& p, ::HIR::TypeRef& ty)
+ {
+ switch(p.tag())
+ {
+ case ::MIR::Param::TAGDEAD: throw "";
+ TU_ARM(p, Constant, pe)
+ return const_to_value(pe, ty);
+ TU_ARM(p, LValue, pe)
+ return read_lvalue_with_ty(pe, ty);
+ }
+ throw "";
+ }
+ Value param_to_value(const ::MIR::Param& p)
+ {
+ ::HIR::TypeRef ty;
+ return param_to_value(p, ty);
+ }
+
+ ValueRef get_value_ref_param(const ::MIR::Param& p, Value& tmp, ::HIR::TypeRef& ty)
+ {
+ switch(p.tag())
+ {
+ case ::MIR::Param::TAGDEAD: throw "";
+ TU_ARM(p, Constant, pe)
+ tmp = const_to_value(pe, ty);
+ return ValueRef(tmp, 0, ty.get_size());
+ TU_ARM(p, LValue, pe)
+ return get_value_and_type(pe, ty);
+ }
+ throw "";
+ }
+};
+
+// ====================================================================
+//
+// ====================================================================
+InterpreterThread::~InterpreterThread()
+{
+ for(size_t i = 0; i < m_stack.size(); i++)
+ {
+ const auto& frame = m_stack[m_stack.size() - 1 - i];
+ ::std::cout << "#" << i << ": ";
+ if( frame.cb )
+ {
+ ::std::cout << "WRAPPER";
+ }
+ else
+ {
+ ::std::cout << frame.fcn.my_path << " BB" << frame.bb_idx << "/";
+ if( frame.stmt_idx == frame.fcn.m_mir.blocks.at(frame.bb_idx).statements.size() )
+ ::std::cout << "TERM";
+ else
+ ::std::cout << frame.stmt_idx;
+ }
+ ::std::cout << ::std::endl;
+ }
+}
+void InterpreterThread::start(const ::HIR::Path& p, ::std::vector<Value> args)
+{
+ assert( this->m_stack.empty() );
+ Value v;
+ if( this->call_path(v, p, ::std::move(args)) )
+ {
+ LOG_TODO("Handle immediate return thread entry");
+ }
+}
+bool InterpreterThread::step_one(Value& out_thread_result)
+{
+ assert( !this->m_stack.empty() );
+ assert( !this->m_stack.back().cb );
+ auto& cur_frame = this->m_stack.back();
+ TRACE_FUNCTION_R(cur_frame.fcn.my_path, "");
+ const auto& bb = cur_frame.fcn.m_mir.blocks.at( cur_frame.bb_idx );
+
+ const size_t MAX_STACK_DEPTH = 40;
+ if( this->m_stack.size() > MAX_STACK_DEPTH )
+ {
+ LOG_ERROR("Maximum stack depth of " << MAX_STACK_DEPTH << " exceeded");
+ }
+
+ MirHelpers state { *this, cur_frame };
+
+ if( cur_frame.stmt_idx < bb.statements.size() )
+ {
+ const auto& stmt = bb.statements[cur_frame.stmt_idx];
+ LOG_DEBUG("=== BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx << ": " << stmt);
+ switch(stmt.tag())
+ {
+ case ::MIR::Statement::TAGDEAD: throw "";
+ TU_ARM(stmt, Assign, se) {
+ Value new_val;
+ switch(se.src.tag())
+ {
+ case ::MIR::RValue::TAGDEAD: throw "";
+ TU_ARM(se.src, Use, re) {
+ new_val = state.read_lvalue(re);
+ } break;
+ TU_ARM(se.src, Constant, re) {
+ new_val = state.const_to_value(re);
+ } break;
+ TU_ARM(se.src, Borrow, re) {
+ ::HIR::TypeRef src_ty;
+ ValueRef src_base_value = state.get_value_and_type(re.val, src_ty);
+ auto alloc = src_base_value.m_alloc;
+ if( !alloc && src_base_value.m_value )
+ {
+ if( !src_base_value.m_value->allocation )
+ {
+ src_base_value.m_value->create_allocation();
+ }
+ alloc = RelocationPtr::new_alloc( src_base_value.m_value->allocation );
+ }
+ if( alloc.is_alloc() )
+ LOG_DEBUG("- alloc=" << alloc << " (" << alloc.alloc() << ")");
+ else
+ LOG_DEBUG("- alloc=" << alloc);
+ size_t ofs = src_base_value.m_offset;
+ const auto meta = src_ty.get_meta_type();
+ auto dst_ty = src_ty.wrapped(TypeWrapper::Ty::Borrow, static_cast<size_t>(re.type));
+
+ // Create the pointer
+ new_val = Value(dst_ty);
+ new_val.write_ptr(0, ofs, ::std::move(alloc));
+ // - Add metadata if required
+ if( meta != RawType::Unreachable )
+ {
+ LOG_ASSERT(src_base_value.m_metadata, "Borrow of an unsized value, but no metadata avaliable");
+ new_val.write_value(POINTER_SIZE, *src_base_value.m_metadata);
+ }
+ } break;
+ TU_ARM(se.src, Cast, re) {
+ // Determine the type of cast, is it a reinterpret or is it a value transform?
+ // - Float <-> integer is a transform, anything else should be a reinterpret.
+ ::HIR::TypeRef src_ty;
+ auto src_value = state.get_value_and_type(re.val, src_ty);
+
+ new_val = Value(re.type);
+ if( re.type == src_ty )
+ {
+ // No-op cast
+ new_val = src_value.read_value(0, re.type.get_size());
+ }
+ else if( const auto* dst_w = re.type.get_wrapper() )
+ {
+ // Destination can only be a raw pointer
+ if( dst_w->type != TypeWrapper::Ty::Pointer ) {
+ LOG_ERROR("Attempting to cast to a type other than a raw pointer - " << re.type);
+ }
+ if( const auto* src_w = src_ty.get_wrapper() )
+ {
+ // Source can be either
+ if( src_w->type != TypeWrapper::Ty::Pointer && src_w->type != TypeWrapper::Ty::Borrow ) {
+ LOG_ERROR("Attempting to cast to a pointer from a non-pointer - " << src_ty);
+ }
+
+ if( src_ty.get_size() < re.type.get_size() )
+ {
+ LOG_ERROR("Casting to a fatter pointer, " << src_ty << " -> " << re.type);
+ }
+ else
+ {
+ new_val = src_value.read_value(0, re.type.get_size());
+ }
+ }
+ else
+ {
+ if( src_ty == RawType::Function )
+ {
+ }
+ else if( src_ty == RawType::USize )
+ {
+ }
+ else
+ {
+ LOG_ERROR("Trying to cast to pointer (" << re.type <<" ) from invalid type (" << src_ty << ")\n");
+ }
+ new_val = src_value.read_value(0, re.type.get_size());
+ }
+ }
+ else if( const auto* src_w = src_ty.get_wrapper() )
+ {
+ if( src_w->type != TypeWrapper::Ty::Pointer && src_w->type != TypeWrapper::Ty::Borrow ) {
+ LOG_ERROR("Attempting to cast to a non-pointer - " << src_ty);
+ }
+ // TODO: MUST be a thin pointer?
+
+ // TODO: MUST be an integer (usize only?)
+ if( re.type != RawType::USize && re.type != RawType::ISize ) {
+ LOG_ERROR("Casting from a pointer to non-usize - " << re.type << " to " << src_ty);
+ throw "ERROR";
+ }
+ new_val = src_value.read_value(0, re.type.get_size());
+ }
+ else
+ {
+ // TODO: What happens if there'a cast of something with a relocation?
+ switch(re.type.inner_type)
+ {
+ case RawType::Unreachable: throw "BUG";
+ case RawType::Composite:
+ case RawType::TraitObject:
+ case RawType::Function:
+ case RawType::Str:
+ case RawType::Unit:
+ LOG_ERROR("Casting to " << re.type << " is invalid");
+ throw "ERROR";
+ case RawType::F32: {
+ float dst_val = 0.0;
+ // Can be an integer, or F64 (pointer is impossible atm)
+ switch(src_ty.inner_type)
+ {
+ case RawType::Unreachable: throw "BUG";
+ case RawType::Composite: throw "ERROR";
+ case RawType::TraitObject: throw "ERROR";
+ case RawType::Function: throw "ERROR";
+ case RawType::Char: throw "ERROR";
+ case RawType::Str: throw "ERROR";
+ case RawType::Unit: throw "ERROR";
+ case RawType::Bool: throw "ERROR";
+ case RawType::F32: throw "BUG";
+ case RawType::F64: dst_val = static_cast<float>( src_value.read_f64(0) ); break;
+ case RawType::USize: throw "TODO";// /*dst_val = src_value.read_usize();*/ break;
+ case RawType::ISize: throw "TODO";// /*dst_val = src_value.read_isize();*/ break;
+ case RawType::U8: dst_val = static_cast<float>( src_value.read_u8 (0) ); break;
+ case RawType::I8: dst_val = static_cast<float>( src_value.read_i8 (0) ); break;
+ case RawType::U16: dst_val = static_cast<float>( src_value.read_u16(0) ); break;
+ case RawType::I16: dst_val = static_cast<float>( src_value.read_i16(0) ); break;
+ case RawType::U32: dst_val = static_cast<float>( src_value.read_u32(0) ); break;
+ case RawType::I32: dst_val = static_cast<float>( src_value.read_i32(0) ); break;
+ case RawType::U64: dst_val = static_cast<float>( src_value.read_u64(0) ); break;
+ case RawType::I64: dst_val = static_cast<float>( src_value.read_i64(0) ); break;
+ case RawType::U128: throw "TODO";// /*dst_val = src_value.read_u128();*/ break;
+ case RawType::I128: throw "TODO";// /*dst_val = src_value.read_i128();*/ break;
+ }
+ new_val.write_f32(0, dst_val);
+ } break;
+ case RawType::F64: {
+ double dst_val = 0.0;
+ // Can be an integer, or F32 (pointer is impossible atm)
+ switch(src_ty.inner_type)
+ {
+ case RawType::Unreachable: throw "BUG";
+ case RawType::Composite: throw "ERROR";
+ case RawType::TraitObject: throw "ERROR";
+ case RawType::Function: throw "ERROR";
+ case RawType::Char: throw "ERROR";
+ case RawType::Str: throw "ERROR";
+ case RawType::Unit: throw "ERROR";
+ case RawType::Bool: throw "ERROR";
+ case RawType::F64: throw "BUG";
+ case RawType::F32: dst_val = static_cast<double>( src_value.read_f32(0) ); break;
+ case RawType::USize: dst_val = static_cast<double>( src_value.read_usize(0) ); break;
+ case RawType::ISize: dst_val = static_cast<double>( src_value.read_isize(0) ); break;
+ case RawType::U8: dst_val = static_cast<double>( src_value.read_u8 (0) ); break;
+ case RawType::I8: dst_val = static_cast<double>( src_value.read_i8 (0) ); break;
+ case RawType::U16: dst_val = static_cast<double>( src_value.read_u16(0) ); break;
+ case RawType::I16: dst_val = static_cast<double>( src_value.read_i16(0) ); break;
+ case RawType::U32: dst_val = static_cast<double>( src_value.read_u32(0) ); break;
+ case RawType::I32: dst_val = static_cast<double>( src_value.read_i32(0) ); break;
+ case RawType::U64: dst_val = static_cast<double>( src_value.read_u64(0) ); break;
+ case RawType::I64: dst_val = static_cast<double>( src_value.read_i64(0) ); break;
+ case RawType::U128: throw "TODO"; /*dst_val = src_value.read_u128();*/ break;
+ case RawType::I128: throw "TODO"; /*dst_val = src_value.read_i128();*/ break;
+ }
+ new_val.write_f64(0, dst_val);
+ } break;
+ case RawType::Bool:
+ LOG_TODO("Cast to " << re.type);
+ case RawType::Char:
+ LOG_TODO("Cast to " << re.type);
+ case RawType::USize:
+ case RawType::U8:
+ case RawType::U16:
+ case RawType::U32:
+ case RawType::U64:
+ case RawType::ISize:
+ case RawType::I8:
+ case RawType::I16:
+ case RawType::I32:
+ case RawType::I64:
+ {
+ uint64_t dst_val = 0;
+ // Can be an integer, or F32 (pointer is impossible atm)
+ switch(src_ty.inner_type)
+ {
+ case RawType::Unreachable:
+ LOG_BUG("Casting unreachable");
+ case RawType::TraitObject:
+ case RawType::Str:
+ LOG_FATAL("Cast of unsized type - " << src_ty);
+ case RawType::Function:
+ LOG_ASSERT(re.type.inner_type == RawType::USize, "Function pointers can only be casted to usize, instead " << re.type);
+ new_val = src_value.read_value(0, re.type.get_size());
+ break;
+ case RawType::Char:
+ LOG_ASSERT(re.type.inner_type == RawType::U32, "Char can only be casted to u32, instead " << re.type);
+ new_val = src_value.read_value(0, 4);
+ break;
+ case RawType::Unit:
+ LOG_FATAL("Cast of unit");
+ case RawType::Composite: {
+ const auto& dt = *src_ty.composite_type;
+ if( dt.variants.size() == 0 ) {
+ LOG_FATAL("Cast of composite - " << src_ty);
+ }
+ // TODO: Check that all variants have the same tag offset
+ LOG_ASSERT(dt.fields.size() == 1, "");
+ LOG_ASSERT(dt.fields[0].first == 0, "");
+ for(size_t i = 0; i < dt.variants.size(); i ++ ) {
+ LOG_ASSERT(dt.variants[i].base_field == 0, "");
+ LOG_ASSERT(dt.variants[i].field_path.empty(), "");
+ }
+ ::HIR::TypeRef tag_ty = dt.fields[0].second;
+ LOG_ASSERT(tag_ty.get_wrapper() == nullptr, "");
+ switch(tag_ty.inner_type)
+ {
+ case RawType::USize:
+ dst_val = static_cast<uint64_t>( src_value.read_usize(0) );
+ if(0)
+ case RawType::ISize:
+ dst_val = static_cast<uint64_t>( src_value.read_isize(0) );
+ if(0)
+ case RawType::U8:
+ dst_val = static_cast<uint64_t>( src_value.read_u8 (0) );
+ if(0)
+ case RawType::I8:
+ dst_val = static_cast<uint64_t>( src_value.read_i8 (0) );
+ if(0)
+ case RawType::U16:
+ dst_val = static_cast<uint64_t>( src_value.read_u16(0) );
+ if(0)
+ case RawType::I16:
+ dst_val = static_cast<uint64_t>( src_value.read_i16(0) );
+ if(0)
+ case RawType::U32:
+ dst_val = static_cast<uint64_t>( src_value.read_u32(0) );
+ if(0)
+ case RawType::I32:
+ dst_val = static_cast<uint64_t>( src_value.read_i32(0) );
+ if(0)
+ case RawType::U64:
+ dst_val = static_cast<uint64_t>( src_value.read_u64(0) );
+ if(0)
+ case RawType::I64:
+ dst_val = static_cast<uint64_t>( src_value.read_i64(0) );
+ break;
+ default:
+ LOG_FATAL("Bad tag type in cast - " << tag_ty);
+ }
+ } if(0)
+ case RawType::Bool:
+ dst_val = static_cast<uint64_t>( src_value.read_u8 (0) );
+ if(0)
+ case RawType::F64:
+ dst_val = static_cast<uint64_t>( src_value.read_f64(0) );
+ if(0)
+ case RawType::F32:
+ dst_val = static_cast<uint64_t>( src_value.read_f32(0) );
+ if(0)
+ case RawType::USize:
+ dst_val = static_cast<uint64_t>( src_value.read_usize(0) );
+ if(0)
+ case RawType::ISize:
+ dst_val = static_cast<uint64_t>( src_value.read_isize(0) );
+ if(0)
+ case RawType::U8:
+ dst_val = static_cast<uint64_t>( src_value.read_u8 (0) );
+ if(0)
+ case RawType::I8:
+ dst_val = static_cast<uint64_t>( src_value.read_i8 (0) );
+ if(0)
+ case RawType::U16:
+ dst_val = static_cast<uint64_t>( src_value.read_u16(0) );
+ if(0)
+ case RawType::I16:
+ dst_val = static_cast<uint64_t>( src_value.read_i16(0) );
+ if(0)
+ case RawType::U32:
+ dst_val = static_cast<uint64_t>( src_value.read_u32(0) );
+ if(0)
+ case RawType::I32:
+ dst_val = static_cast<uint64_t>( src_value.read_i32(0) );
+ if(0)
+ case RawType::U64:
+ dst_val = static_cast<uint64_t>( src_value.read_u64(0) );
+ if(0)
+ case RawType::I64:
+ dst_val = static_cast<uint64_t>( src_value.read_i64(0) );
+
+ switch(re.type.inner_type)
+ {
+ case RawType::USize:
+ new_val.write_usize(0, dst_val);
+ break;
+ case RawType::U8:
+ new_val.write_u8(0, static_cast<uint8_t>(dst_val));
+ break;
+ case RawType::U16:
+ new_val.write_u16(0, static_cast<uint16_t>(dst_val));
+ break;
+ case RawType::U32:
+ new_val.write_u32(0, static_cast<uint32_t>(dst_val));
+ break;
+ case RawType::U64:
+ new_val.write_u64(0, dst_val);
+ break;
+ case RawType::ISize:
+ new_val.write_usize(0, static_cast<int64_t>(dst_val));
+ break;
+ case RawType::I8:
+ new_val.write_i8(0, static_cast<int8_t>(dst_val));
+ break;
+ case RawType::I16:
+ new_val.write_i16(0, static_cast<int16_t>(dst_val));
+ break;
+ case RawType::I32:
+ new_val.write_i32(0, static_cast<int32_t>(dst_val));
+ break;
+ case RawType::I64:
+ new_val.write_i64(0, static_cast<int64_t>(dst_val));
+ break;
+ default:
+ throw "";
+ }
+ break;
+ case RawType::U128: throw "TODO"; /*dst_val = src_value.read_u128();*/ break;
+ case RawType::I128: throw "TODO"; /*dst_val = src_value.read_i128();*/ break;
+ }
+ } break;
+ case RawType::U128:
+ case RawType::I128:
+ LOG_TODO("Cast to " << re.type);
+ }
+ }
+ } break;
+ TU_ARM(se.src, BinOp, re) {
+ ::HIR::TypeRef ty_l, ty_r;
+ Value tmp_l, tmp_r;
+ auto v_l = state.get_value_ref_param(re.val_l, tmp_l, ty_l);
+ auto v_r = state.get_value_ref_param(re.val_r, tmp_r, ty_r);
+ LOG_DEBUG(v_l << " (" << ty_l <<") ? " << v_r << " (" << ty_r <<")");
+
+ switch(re.op)
+ {
+ case ::MIR::eBinOp::EQ:
+ case ::MIR::eBinOp::NE:
+ case ::MIR::eBinOp::GT:
+ case ::MIR::eBinOp::GE:
+ case ::MIR::eBinOp::LT:
+ case ::MIR::eBinOp::LE: {
+ LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
+ int res = 0;
+ // TODO: Handle comparison of the relocations too
+
+ const auto& alloc_l = v_l.m_value ? v_l.m_value->allocation : v_l.m_alloc;
+ const auto& alloc_r = v_r.m_value ? v_r.m_value->allocation : v_r.m_alloc;
+ auto reloc_l = alloc_l ? v_l.get_relocation(v_l.m_offset) : RelocationPtr();
+ auto reloc_r = alloc_r ? v_r.get_relocation(v_r.m_offset) : RelocationPtr();
+
+ if( reloc_l != reloc_r )
+ {
+ res = (reloc_l < reloc_r ? -1 : 1);
+ }
+ LOG_DEBUG("res=" << res << ", " << reloc_l << " ? " << reloc_r);
+
+ if( const auto* w = ty_l.get_wrapper() )
+ {
+ if( w->type == TypeWrapper::Ty::Pointer )
+ {
+ // TODO: Technically only EQ/NE are valid.
+
+ res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0));
+
+ // Compare fat metadata.
+ if( res == 0 && v_l.m_size > POINTER_SIZE )
+ {
+ reloc_l = v_l.get_relocation(POINTER_SIZE);
+ reloc_r = v_r.get_relocation(POINTER_SIZE);
+
+ if( res == 0 && reloc_l != reloc_r )
+ {
+ res = (reloc_l < reloc_r ? -1 : 1);
+ }
+ res = res != 0 ? res : Ops::do_compare(v_l.read_usize(POINTER_SIZE), v_r.read_usize(POINTER_SIZE));
+ }
+ }
+ else
+ {
+ LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l);
+ }
+ }
+ else
+ {
+ switch(ty_l.inner_type)
+ {
+ case RawType::U64: res = res != 0 ? res : Ops::do_compare(v_l.read_u64(0), v_r.read_u64(0)); break;
+ case RawType::U32: res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0)); break;
+ case RawType::U16: res = res != 0 ? res : Ops::do_compare(v_l.read_u16(0), v_r.read_u16(0)); break;
+ case RawType::U8 : res = res != 0 ? res : Ops::do_compare(v_l.read_u8 (0), v_r.read_u8 (0)); break;
+ case RawType::I64: res = res != 0 ? res : Ops::do_compare(v_l.read_i64(0), v_r.read_i64(0)); break;
+ case RawType::I32: res = res != 0 ? res : Ops::do_compare(v_l.read_i32(0), v_r.read_i32(0)); break;
+ case RawType::I16: res = res != 0 ? res : Ops::do_compare(v_l.read_i16(0), v_r.read_i16(0)); break;
+ case RawType::I8 : res = res != 0 ? res : Ops::do_compare(v_l.read_i8 (0), v_r.read_i8 (0)); break;
+ case RawType::USize: res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); break;
+ case RawType::ISize: res = res != 0 ? res : Ops::do_compare(v_l.read_isize(0), v_r.read_isize(0)); break;
+ default:
+ LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l);
+ }
+ }
+ bool res_bool;
+ switch(re.op)
+ {
+ case ::MIR::eBinOp::EQ: res_bool = (res == 0); break;
+ case ::MIR::eBinOp::NE: res_bool = (res != 0); break;
+ case ::MIR::eBinOp::GT: res_bool = (res == 1); break;
+ case ::MIR::eBinOp::GE: res_bool = (res == 1 || res == 0); break;
+ case ::MIR::eBinOp::LT: res_bool = (res == -1); break;
+ case ::MIR::eBinOp::LE: res_bool = (res == -1 || res == 0); break;
+ break;
+ default:
+ LOG_BUG("Unknown comparison");
+ }
+ new_val = Value(::HIR::TypeRef(RawType::Bool));
+ new_val.write_u8(0, res_bool ? 1 : 0);
+ } break;
+ case ::MIR::eBinOp::BIT_SHL:
+ case ::MIR::eBinOp::BIT_SHR: {
+ LOG_ASSERT(ty_l.get_wrapper() == nullptr, "Bitwise operator on non-primitive - " << ty_l);
+ LOG_ASSERT(ty_r.get_wrapper() == nullptr, "Bitwise operator with non-primitive - " << ty_r);
+ size_t max_bits = ty_r.get_size() * 8;
+ uint8_t shift;
+ auto check_cast = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast<uint8_t>(v); };
+ switch(ty_r.inner_type)
+ {
+ case RawType::U64: shift = check_cast(v_r.read_u64(0)); break;
+ case RawType::U32: shift = check_cast(v_r.read_u32(0)); break;
+ case RawType::U16: shift = check_cast(v_r.read_u16(0)); break;
+ case RawType::U8 : shift = check_cast(v_r.read_u8 (0)); break;
+ case RawType::I64: shift = check_cast(v_r.read_i64(0)); break;
+ case RawType::I32: shift = check_cast(v_r.read_i32(0)); break;
+ case RawType::I16: shift = check_cast(v_r.read_i16(0)); break;
+ case RawType::I8 : shift = check_cast(v_r.read_i8 (0)); break;
+ case RawType::USize: shift = check_cast(v_r.read_usize(0)); break;
+ case RawType::ISize: shift = check_cast(v_r.read_isize(0)); break;
+ default:
+ LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r);
+ }
+ new_val = Value(ty_l);
+ switch(ty_l.inner_type)
+ {
+ // TODO: U128
+ case RawType::U64: new_val.write_u64(0, Ops::do_bitwise(v_l.read_u64(0), static_cast<uint64_t>(shift), re.op)); break;
+ case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast<uint32_t>(shift), re.op)); break;
+ case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast<uint16_t>(shift), re.op)); break;
+ case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast<uint8_t >(shift), re.op)); break;
+ case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast<uint64_t>(shift), re.op)); break;
+ // TODO: Is signed allowed?
+ default:
+ LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r);
+ }
+ } break;
+ case ::MIR::eBinOp::BIT_AND:
+ case ::MIR::eBinOp::BIT_OR:
+ case ::MIR::eBinOp::BIT_XOR:
+ LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
+ LOG_ASSERT(ty_l.get_wrapper() == nullptr, "Bitwise operator on non-primitive - " << ty_l);
+ new_val = Value(ty_l);
+ switch(ty_l.inner_type)
+ {
+ // TODO: U128/I128
+ case RawType::U64:
+ case RawType::I64:
+ new_val.write_u64( 0, Ops::do_bitwise(v_l.read_u64(0), v_r.read_u64(0), re.op) );
+ break;
+ case RawType::U32:
+ case RawType::I32:
+ new_val.write_u32( 0, static_cast<uint32_t>(Ops::do_bitwise(v_l.read_u32(0), v_r.read_u32(0), re.op)) );
+ break;
+ case RawType::U16:
+ case RawType::I16:
+ new_val.write_u16( 0, static_cast<uint16_t>(Ops::do_bitwise(v_l.read_u16(0), v_r.read_u16(0), re.op)) );
+ break;
+ case RawType::U8:
+ case RawType::I8:
+ new_val.write_u8 ( 0, static_cast<uint8_t >(Ops::do_bitwise(v_l.read_u8 (0), v_r.read_u8 (0), re.op)) );
+ break;
+ case RawType::USize:
+ case RawType::ISize:
+ new_val.write_usize( 0, Ops::do_bitwise(v_l.read_usize(0), v_r.read_usize(0), re.op) );
+ break;
+ default:
+ LOG_TODO("BinOp bitwise - " << se.src << " w/ " << ty_l);
+ }
+
+ break;
+ default:
+ LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
+ auto val_l = PrimitiveValueVirt::from_value(ty_l, v_l);
+ auto val_r = PrimitiveValueVirt::from_value(ty_r, v_r);
+ switch(re.op)
+ {
+ case ::MIR::eBinOp::ADD: val_l.get().add( val_r.get() ); break;
+ case ::MIR::eBinOp::SUB: val_l.get().subtract( val_r.get() ); break;
+ case ::MIR::eBinOp::MUL: val_l.get().multiply( val_r.get() ); break;
+ case ::MIR::eBinOp::DIV: val_l.get().divide( val_r.get() ); break;
+ case ::MIR::eBinOp::MOD: val_l.get().modulo( val_r.get() ); break;
+
+ default:
+ LOG_TODO("Unsupported binary operator?");
+ }
+ new_val = Value(ty_l);
+ val_l.get().write_to_value(new_val, 0);
+ break;
+ }
+ } break;
+ TU_ARM(se.src, UniOp, re) {
+ ::HIR::TypeRef ty;
+ auto v = state.get_value_and_type(re.val, ty);
+ LOG_ASSERT(ty.get_wrapper() == nullptr, "UniOp on wrapped type - " << ty);
+ new_val = Value(ty);
+ switch(re.op)
+ {
+ case ::MIR::eUniOp::INV:
+ switch(ty.inner_type)
+ {
+ case RawType::U128:
+ case RawType::I128:
+ LOG_TODO("UniOp::INV U128");
+ case RawType::U64:
+ case RawType::I64:
+ new_val.write_u64( 0, ~v.read_u64(0) );
+ break;
+ case RawType::U32:
+ case RawType::I32:
+ new_val.write_u32( 0, ~v.read_u32(0) );
+ break;
+ case RawType::U16:
+ case RawType::I16:
+ new_val.write_u16( 0, ~v.read_u16(0) );
+ break;
+ case RawType::U8:
+ case RawType::I8:
+ new_val.write_u8 ( 0, ~v.read_u8 (0) );
+ break;
+ case RawType::USize:
+ case RawType::ISize:
+ new_val.write_usize( 0, ~v.read_usize(0) );
+ break;
+ case RawType::Bool:
+ new_val.write_u8 ( 0, v.read_u8 (0) == 0 );
+ break;
+ default:
+ LOG_TODO("UniOp::INV - w/ type " << ty);
+ }
+ break;
+ case ::MIR::eUniOp::NEG:
+ switch(ty.inner_type)
+ {
+ case RawType::I128:
+ LOG_TODO("UniOp::NEG I128");
+ case RawType::I64:
+ new_val.write_i64( 0, -v.read_i64(0) );
+ break;
+ case RawType::I32:
+ new_val.write_i32( 0, -v.read_i32(0) );
+ break;
+ case RawType::I16:
+ new_val.write_i16( 0, -v.read_i16(0) );
+ break;
+ case RawType::I8:
+ new_val.write_i8 ( 0, -v.read_i8 (0) );
+ break;
+ case RawType::ISize:
+ new_val.write_isize( 0, -v.read_isize(0) );
+ break;
+ default:
+ LOG_ERROR("UniOp::INV not valid on type " << ty);
+ }
+ break;
+ }
+ } break;
+ TU_ARM(se.src, DstMeta, re) {
+ auto ptr = state.get_value_ref(re.val);
+
+ ::HIR::TypeRef dst_ty;
+ state.get_value_and_type(se.dst, dst_ty);
+ new_val = ptr.read_value(POINTER_SIZE, dst_ty.get_size());
+ } break;
+ TU_ARM(se.src, DstPtr, re) {
+ auto ptr = state.get_value_ref(re.val);
+
+ new_val = ptr.read_value(0, POINTER_SIZE);
+ } break;
+ TU_ARM(se.src, MakeDst, re) {
+ // - Get target type, just for some assertions
+ ::HIR::TypeRef dst_ty;
+ state.get_value_and_type(se.dst, dst_ty);
+ new_val = Value(dst_ty);
+
+ auto ptr = state.param_to_value(re.ptr_val );
+ auto meta = state.param_to_value(re.meta_val);
+ LOG_DEBUG("ty=" << dst_ty << ", ptr=" << ptr << ", meta=" << meta);
+
+ new_val.write_value(0, ::std::move(ptr));
+ new_val.write_value(POINTER_SIZE, ::std::move(meta));
+ } break;
+ TU_ARM(se.src, Tuple, re) {
+ ::HIR::TypeRef dst_ty;
+ state.get_value_and_type(se.dst, dst_ty);
+ new_val = Value(dst_ty);
+
+ for(size_t i = 0; i < re.vals.size(); i++)
+ {
+ auto fld_ofs = dst_ty.composite_type->fields.at(i).first;
+ new_val.write_value(fld_ofs, state.param_to_value(re.vals[i]));
+ }
+ } break;
+ TU_ARM(se.src, Array, re) {
+ ::HIR::TypeRef dst_ty;
+ state.get_value_and_type(se.dst, dst_ty);
+ new_val = Value(dst_ty);
+ // TODO: Assert that type is an array
+ auto inner_ty = dst_ty.get_inner();
+ size_t stride = inner_ty.get_size();
+
+ size_t ofs = 0;
+ for(const auto& v : re.vals)
+ {
+ new_val.write_value(ofs, state.param_to_value(v));
+ ofs += stride;
+ }
+ } break;
+ TU_ARM(se.src, SizedArray, re) {
+ ::HIR::TypeRef dst_ty;
+ state.get_value_and_type(se.dst, dst_ty);
+ new_val = Value(dst_ty);
+ // TODO: Assert that type is an array
+ auto inner_ty = dst_ty.get_inner();
+ size_t stride = inner_ty.get_size();
+
+ size_t ofs = 0;
+ for(size_t i = 0; i < re.count; i++)
+ {
+ new_val.write_value(ofs, state.param_to_value(re.val));
+ ofs += stride;
+ }
+ } break;
+ TU_ARM(se.src, Variant, re) {
+ // 1. Get the composite by path.
+ const auto& data_ty = this->m_modtree.get_composite(re.path);
+ auto dst_ty = ::HIR::TypeRef(&data_ty);
+ new_val = Value(dst_ty);
+ // Three cases:
+ // - Unions (no tag)
+ // - Data enums (tag and data)
+ // - Value enums (no data)
+ const auto& var = data_ty.variants.at(re.index);
+ if( var.data_field != SIZE_MAX )
+ {
+ const auto& fld = data_ty.fields.at(re.index);
+
+ new_val.write_value(fld.first, state.param_to_value(re.val));
+ }
+ if( var.base_field != SIZE_MAX )
+ {
+ ::HIR::TypeRef tag_ty;
+ size_t tag_ofs = dst_ty.get_field_ofs(var.base_field, var.field_path, tag_ty);
+ LOG_ASSERT(tag_ty.get_size() == var.tag_data.size(), "");
+ new_val.write_bytes(tag_ofs, var.tag_data.data(), var.tag_data.size());
+ }
+ else
+ {
+ // Union, no tag
+ }
+ LOG_DEBUG("Variant " << new_val);
+ } break;
+ TU_ARM(se.src, Struct, re) {
+ const auto& data_ty = m_modtree.get_composite(re.path);
+
+ ::HIR::TypeRef dst_ty;
+ state.get_value_and_type(se.dst, dst_ty);
+ new_val = Value(dst_ty);
+ LOG_ASSERT(dst_ty.composite_type == &data_ty, "Destination type of RValue::Struct isn't the same as the input");
+
+ for(size_t i = 0; i < re.vals.size(); i++)
+ {
+ auto fld_ofs = data_ty.fields.at(i).first;
+ new_val.write_value(fld_ofs, state.param_to_value(re.vals[i]));
+ }
+ } break;
+ }
+ LOG_DEBUG("- new_val=" << new_val);
+ state.write_lvalue(se.dst, ::std::move(new_val));
+ } break;
+ case ::MIR::Statement::TAG_Asm:
+ LOG_TODO(stmt);
+ break;
+ TU_ARM(stmt, Drop, se) {
+ if( se.flag_idx == ~0u || cur_frame.drop_flags.at(se.flag_idx) )
+ {
+ ::HIR::TypeRef ty;
+ auto v = state.get_value_and_type(se.slot, ty);
+
+ // - Take a pointer to the inner
+ auto alloc = v.m_alloc;
+ if( !alloc )
+ {
+ if( !v.m_value->allocation )
+ {
+ v.m_value->create_allocation();
+ }
+ alloc = RelocationPtr::new_alloc( v.m_value->allocation );
+ }
+ size_t ofs = v.m_offset;
+ assert(ty.get_meta_type() == RawType::Unreachable);
+
+ auto ptr_ty = ty.wrapped(TypeWrapper::Ty::Borrow, 2);
+
+ auto ptr_val = Value::new_pointer(ptr_ty, ofs, ::std::move(alloc));
+
+ if( !drop_value(ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW) )
+ {
+ return false;
+ }
+ }
+ } break;
+ TU_ARM(stmt, SetDropFlag, se) {
+ bool val = (se.other == ~0u ? false : cur_frame.drop_flags.at(se.other)) != se.new_val;
+ LOG_DEBUG("- " << val);
+ cur_frame.drop_flags.at(se.idx) = val;
+ } break;
+ case ::MIR::Statement::TAG_ScopeEnd:
+ LOG_TODO(stmt);
+ break;
+ }
+
+ cur_frame.stmt_idx += 1;
+ }
+ else
+ {
+ LOG_DEBUG("=== BB" << cur_frame.bb_idx << "/TERM: " << bb.terminator);
+ switch(bb.terminator.tag())
+ {
+ case ::MIR::Terminator::TAGDEAD: throw "";
+ TU_ARM(bb.terminator, Incomplete, _te)
+ LOG_TODO("Terminator::Incomplete hit");
+ TU_ARM(bb.terminator, Diverge, _te)
+ LOG_TODO("Terminator::Diverge hit");
+ TU_ARM(bb.terminator, Panic, _te)
+ LOG_TODO("Terminator::Panic");
+ TU_ARM(bb.terminator, Goto, te)
+ cur_frame.bb_idx = te;
+ break;
+ TU_ARM(bb.terminator, Return, _te)
+ LOG_DEBUG("RETURN " << cur_frame.ret);
+ return this->pop_stack(out_thread_result);
+ TU_ARM(bb.terminator, If, te) {
+ uint8_t v = state.get_value_ref(te.cond).read_u8(0);
+ LOG_ASSERT(v == 0 || v == 1, "");
+ cur_frame.bb_idx = v ? te.bb0 : te.bb1;
+ } break;
+ TU_ARM(bb.terminator, Switch, te) {
+ ::HIR::TypeRef ty;
+ auto v = state.get_value_and_type(te.val, ty);
+ LOG_ASSERT(ty.get_wrapper() == nullptr, "Matching on wrapped value - " << ty);
+ LOG_ASSERT(ty.inner_type == RawType::Composite, "Matching on non-coposite - " << ty);
+
+ // TODO: Convert the variant list into something that makes it easier to switch on.
+ size_t found_target = SIZE_MAX;
+ size_t default_target = SIZE_MAX;
+ for(size_t i = 0; i < ty.composite_type->variants.size(); i ++)
+ {
+ const auto& var = ty.composite_type->variants[i];
+ if( var.tag_data.size() == 0 )
+ {
+ // Save as the default, error for multiple defaults
+ if( default_target != SIZE_MAX )
+ {
+ LOG_FATAL("Two variants with no tag in Switch - " << ty);
+ }
+ default_target = i;
+ }
+ else
+ {
+ // Get offset, read the value.
+ ::HIR::TypeRef tag_ty;
+ size_t tag_ofs = ty.get_field_ofs(var.base_field, var.field_path, tag_ty);
+ // Read the value bytes
+ ::std::vector<char> tmp( var.tag_data.size() );
+ v.read_bytes(tag_ofs, const_cast<char*>(tmp.data()), tmp.size());
+ if( v.get_relocation(tag_ofs) )
+ continue ;
+ if( ::std::memcmp(tmp.data(), var.tag_data.data(), tmp.size()) == 0 )
+ {
+ found_target = i;
+ break ;
+ }
+ }
+ }
+
+ if( found_target == SIZE_MAX )
+ {
+ found_target = default_target;
+ }
+ if( found_target == SIZE_MAX )
+ {
+ LOG_FATAL("Terminator::Switch on " << ty << " didn't find a variant");
+ }
+ cur_frame.bb_idx = te.targets.at(found_target);
+ } break;
+ TU_ARM(bb.terminator, SwitchValue, _te)
+ LOG_TODO("Terminator::SwitchValue");
+ TU_ARM(bb.terminator, Call, te) {
+ ::std::vector<Value> sub_args; sub_args.reserve(te.args.size());
+ for(const auto& a : te.args)
+ {
+ sub_args.push_back( state.param_to_value(a) );
+ LOG_DEBUG("#" << (sub_args.size() - 1) << " " << sub_args.back());
+ }
+ Value rv;
+ if( te.fcn.is_Intrinsic() )
+ {
+ const auto& fe = te.fcn.as_Intrinsic();
+ if( !this->call_intrinsic(rv, fe.name, fe.params, ::std::move(sub_args)) )
+ {
+ // Early return, don't want to update stmt_idx yet
+ return false;
+ }
+ }
+ else
+ {
+ RelocationPtr fcn_alloc_ptr;
+ const ::HIR::Path* fcn_p;
+ if( te.fcn.is_Path() ) {
+ fcn_p = &te.fcn.as_Path();
+ }
+ else {
+ ::HIR::TypeRef ty;
+ auto v = state.get_value_and_type(te.fcn.as_Value(), ty);
+ LOG_DEBUG("> Indirect call " << v);
+ // TODO: Assert type
+ // TODO: Assert offset/content.
+ assert(v.read_usize(0) == 0);
+ fcn_alloc_ptr = v.get_relocation(v.m_offset);
+ if( !fcn_alloc_ptr )
+ LOG_FATAL("Calling value with no relocation - " << v);
+ LOG_ASSERT(fcn_alloc_ptr.get_ty() == RelocationPtr::Ty::Function, "Calling value that isn't a function pointer");
+ fcn_p = &fcn_alloc_ptr.fcn();
+ }
+
+ LOG_DEBUG("Call " << *fcn_p);
+ if( !this->call_path(rv, *fcn_p, ::std::move(sub_args)) )
+ {
+ // Early return, don't want to update stmt_idx yet
+ return false;
+ }
+ }
+ LOG_DEBUG(te.ret_val << " = " << rv << " (resume " << cur_frame.fcn.my_path << ")");
+ state.write_lvalue(te.ret_val, rv);
+ cur_frame.bb_idx = te.ret_block;
+ } break;
+ }
+ cur_frame.stmt_idx = 0;
+ }
+
+ return false;
+}
+bool InterpreterThread::pop_stack(Value& out_thread_result)
+{
+ assert( !this->m_stack.empty() );
+
+ auto res_v = ::std::move(this->m_stack.back().ret);
+ this->m_stack.pop_back();
+
+ if( this->m_stack.empty() )
+ {
+ LOG_DEBUG("Thread complete, result " << res_v);
+ out_thread_result = ::std::move(res_v);
+ return true;
+ }
+ else
+ {
+ // Handle callback wrappers (e.g. for __rust_maybe_catch_panic, drop_value)
+ if( this->m_stack.back().cb )
+ {
+ if( !this->m_stack.back().cb(res_v, ::std::move(res_v)) )
+ {
+ return false;
+ }
+ this->m_stack.pop_back();
+ assert( !this->m_stack.empty() );
+ assert( !this->m_stack.back().cb );
+ }
+
+ auto& cur_frame = this->m_stack.back();
+ MirHelpers state { *this, cur_frame };
+
+ const auto& blk = cur_frame.fcn.m_mir.blocks.at( cur_frame.bb_idx );
+ if( cur_frame.stmt_idx < blk.statements.size() )
+ {
+ assert( blk.statements[cur_frame.stmt_idx].is_Drop() );
+ cur_frame.stmt_idx ++;
+ LOG_DEBUG("DROP complete (resume " << cur_frame.fcn.my_path << ")");
+ }
+ else
+ {
+ assert( blk.terminator.is_Call() );
+ const auto& te = blk.terminator.as_Call();
+
+ LOG_DEBUG(te.ret_val << " = " << res_v << " (resume " << cur_frame.fcn.my_path << ")");
+
+ state.write_lvalue(te.ret_val, res_v);
+ cur_frame.stmt_idx = 0;
+ cur_frame.bb_idx = te.ret_block;
+ }
+
+ return false;
+ }
+}
+
+InterpreterThread::StackFrame::StackFrame(const Function& fcn, ::std::vector<Value> args):
+ fcn(fcn),
+ ret( fcn.ret_ty ),
+ args( ::std::move(args) ),
+ locals( ),
+ drop_flags( fcn.m_mir.drop_flags ),
+ bb_idx(0),
+ stmt_idx(0)
+{
+ this->locals.reserve( fcn.m_mir.locals.size() );
+ for(const auto& ty : fcn.m_mir.locals)
+ {
+ if( ty == RawType::Unreachable ) {
+ // HACK: Locals can be !, but they can NEVER be accessed
+ this->locals.push_back( Value() );
+ }
+ else {
+ this->locals.push_back( Value(ty) );
+ }
+ }
+}
+bool InterpreterThread::call_path(Value& ret, const ::HIR::Path& path, ::std::vector<Value> args)
+{
+ // TODO: Support overriding certain functions
+ {
+ if( path == ::HIR::SimplePath { "std", { "sys", "imp", "c", "SetThreadStackGuarantee" } } )
+ {
+ ret = Value::new_i32(120); //ERROR_CALL_NOT_IMPLEMENTED
+ return true;
+ }
+
+ // - No guard page needed
+ if( path == ::HIR::SimplePath { "std", {"sys", "imp", "thread", "guard", "init" } } )
+ {
+ ret = Value::with_size(16, false);
+ ret.write_u64(0, 0);
+ ret.write_u64(8, 0);
+ return true;
+ }
+
+ // - No stack overflow handling needed
+ if( path == ::HIR::SimplePath { "std", { "sys", "imp", "stack_overflow", "imp", "init" } } )
+ {
+ return true;
+ }
+ }
+
+ const auto& fcn = m_modtree.get_function(path);
+
+ if( fcn.external.link_name != "" )
+ {
+ // External function!
+ return this->call_extern(ret, fcn.external.link_name, fcn.external.link_abi, ::std::move(args));
+ }
+
+ this->m_stack.push_back(StackFrame(fcn, ::std::move(args)));
+ return false;
+}
+
+extern "C" {
+ long sysconf(int);
+ ssize_t write(int, const void*, size_t);
+}
+bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, const ::std::string& abi, ::std::vector<Value> args)
+{
+ if( link_name == "__rust_allocate" )
+ {
+ auto size = args.at(0).read_usize(0);
+ auto align = args.at(1).read_usize(0);
+ LOG_DEBUG("__rust_allocate(size=" << size << ", align=" << align << ")");
+ auto rty = ::HIR::TypeRef(RawType::Unit).wrap( TypeWrapper::Ty::Pointer, 0 );
+
+ // TODO: Use the alignment when making an allocation?
+ rv = Value::new_pointer(rty, 0, RelocationPtr::new_alloc(Allocation::new_alloc(size)));
+ }
+ else if( link_name == "__rust_reallocate" )
+ {
+ LOG_ASSERT(args.at(0).allocation, "__rust_reallocate first argument doesn't have an allocation");
+ auto alloc_ptr = args.at(0).get_relocation(0);
+ auto ptr_ofs = args.at(0).read_usize(0);
+ LOG_ASSERT(ptr_ofs == 0, "__rust_reallocate with offset pointer");
+ auto oldsize = args.at(1).read_usize(0);
+ auto newsize = args.at(2).read_usize(0);
+ auto align = args.at(3).read_usize(0);
+ LOG_DEBUG("__rust_reallocate(ptr=" << alloc_ptr << ", oldsize=" << oldsize << ", newsize=" << newsize << ", align=" << align << ")");
+
+ LOG_ASSERT(alloc_ptr, "__rust_reallocate with no backing allocation attached to pointer");
+ LOG_ASSERT(alloc_ptr.is_alloc(), "__rust_reallocate with no backing allocation attached to pointer");
+ auto& alloc = alloc_ptr.alloc();
+ // TODO: Check old size and alignment against allocation.
+ alloc.data.resize( (newsize + 8-1) / 8 );
+ alloc.mask.resize( (newsize + 8-1) / 8 );
+ // TODO: Should this instead make a new allocation to catch use-after-free?
+ rv = ::std::move(args.at(0));
+ }
+ else if( link_name == "__rust_deallocate" )
+ {
+ LOG_ASSERT(args.at(0).allocation, "__rust_deallocate first argument doesn't have an allocation");
+ auto alloc_ptr = args.at(0).get_relocation(0);
+ auto ptr_ofs = args.at(0).read_usize(0);
+ LOG_ASSERT(ptr_ofs == 0, "__rust_deallocate with offset pointer");
+ LOG_DEBUG("__rust_deallocate(ptr=" << alloc_ptr << ")");
+
+ LOG_ASSERT(alloc_ptr, "__rust_deallocate with no backing allocation attached to pointer");
+ LOG_ASSERT(alloc_ptr.is_alloc(), "__rust_deallocate with no backing allocation attached to pointer");
+ auto& alloc = alloc_ptr.alloc();
+ alloc.mark_as_freed();
+ // Just let it drop.
+ rv = Value();
+ }
+ else if( link_name == "__rust_maybe_catch_panic" )
+ {
+ auto fcn_path = args.at(0).get_relocation(0).fcn();
+ auto arg = args.at(1);
+ auto data_ptr = args.at(2).read_pointer_valref_mut(0, POINTER_SIZE);
+ auto vtable_ptr = args.at(3).read_pointer_valref_mut(0, POINTER_SIZE);
+
+ ::std::vector<Value> sub_args;
+ sub_args.push_back( ::std::move(arg) );
+
+ this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)->bool{
+ out_rv = Value::new_u32(0);
+ return true;
+ }));
+
+ // TODO: Catch the panic out of this.
+ if( this->call_path(rv, fcn_path, ::std::move(sub_args)) )
+ {
+ bool v = this->pop_stack(rv);
+ assert( v == false );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if( link_name == "__rust_start_panic" )
+ {
+ LOG_TODO("__rust_start_panic");
+ }
+ else if( link_name == "rust_begin_unwind" )
+ {
+ LOG_TODO("rust_begin_unwind");
+ }
+#ifdef _WIN32
+ // WinAPI functions used by libstd
+ else if( link_name == "AddVectoredExceptionHandler" )
+ {
+ LOG_DEBUG("Call `AddVectoredExceptionHandler` - Ignoring and returning non-null");
+ rv = Value::new_usize(1);
+ }
+ else if( link_name == "GetModuleHandleW" )
+ {
+ LOG_ASSERT(args.at(0).allocation.is_alloc(), "");
+ const auto& tgt_alloc = args.at(0).allocation.alloc().get_relocation(0);
+ const void* arg0 = (tgt_alloc ? tgt_alloc.alloc().data_ptr() : nullptr);
+ //extern void* GetModuleHandleW(const void* s);
+ if(arg0) {
+ LOG_DEBUG("GetModuleHandleW(" << tgt_alloc.alloc() << ")");
+ }
+ else {
+ LOG_DEBUG("GetModuleHandleW(NULL)");
+ }
+
+ auto ret = GetModuleHandleW(static_cast<LPCWSTR>(arg0));
+ if(ret)
+ {
+ rv = Value::new_ffiptr(FFIPointer { "GetModuleHandleW", ret, 0 });
+ }
+ else
+ {
+ rv = Value(::HIR::TypeRef(RawType::USize));
+ rv.create_allocation();
+ rv.write_usize(0,0);
+ }
+ }
+ else if( link_name == "GetProcAddress" )
+ {
+ LOG_ASSERT(args.at(0).allocation.is_alloc(), "");
+ const auto& handle_alloc = args.at(0).allocation.alloc().get_relocation(0);
+ LOG_ASSERT(args.at(1).allocation.is_alloc(), "");
+ const auto& sym_alloc = args.at(1).allocation.alloc().get_relocation(0);
+
+ // TODO: Ensure that first arg is a FFI pointer with offset+size of zero
+ void* handle = handle_alloc.ffi().ptr_value;
+ // TODO: Get either a FFI data pointer, or a inner data pointer
+ const void* symname = sym_alloc.alloc().data_ptr();
+ // TODO: Sanity check that it's a valid c string within its allocation
+ LOG_DEBUG("FFI GetProcAddress(" << handle << ", \"" << static_cast<const char*>(symname) << "\")");
+
+ auto ret = GetProcAddress(static_cast<HMODULE>(handle), static_cast<LPCSTR>(symname));
+
+ if( ret )
+ {
+ rv = Value::new_ffiptr(FFIPointer { "GetProcAddress", ret, 0 });
+ }
+ else
+ {
+ rv = Value(::HIR::TypeRef(RawType::USize));
+ rv.create_allocation();
+ rv.write_usize(0,0);
+ }
+ }
+#else
+ // POSIX
+ else if( link_name == "write" )
+ {
+ auto fd = args.at(0).read_i32(0);
+ auto count = args.at(2).read_isize(0);
+ const auto* buf = args.at(1).read_pointer_const(0, count);
+
+ ssize_t val = write(fd, buf, count);
+
+ rv = Value::new_isize(val);
+ }
+ else if( link_name == "sysconf" )
+ {
+ auto name = args.at(0).read_i32(0);
+ LOG_DEBUG("FFI sysconf(" << name << ")");
+
+ long val = sysconf(name);
+
+ rv = Value::new_usize(val);
+ }
+ else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" || link_name == "pthread_mutex_destroy" )
+ {
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_rwlock_rdlock" )
+ {
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" )
+ {
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_condattr_init" || link_name == "pthread_condattr_destroy" || link_name == "pthread_condattr_setclock" )
+ {
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" )
+ {
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_key_create" )
+ {
+ auto key_ref = args.at(0).read_pointer_valref_mut(0, 4);
+
+ auto key = ThreadState::s_next_tls_key ++;
+ key_ref.m_alloc.alloc().write_u32( key_ref.m_offset, key );
+
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_getspecific" )
+ {
+ auto key = args.at(0).read_u32(0);
+
+ // Get a pointer-sized value from storage
+ uint64_t v = key < m_thread.tls_values.size() ? m_thread.tls_values[key] : 0;
+
+ rv = Value::new_usize(v);
+ }
+ else if( link_name == "pthread_setspecific" )
+ {
+ auto key = args.at(0).read_u32(0);
+ auto v = args.at(1).read_u64(0);
+
+ // Get a pointer-sized value from storage
+ if( key >= m_thread.tls_values.size() ) {
+ m_thread.tls_values.resize(key+1);
+ }
+ m_thread.tls_values[key] = v;
+
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_key_delete" )
+ {
+ rv = Value::new_i32(0);
+ }
+#endif
+ // std C
+ else if( link_name == "signal" )
+ {
+ LOG_DEBUG("Call `signal` - Ignoring and returning SIG_IGN");
+ rv = Value(::HIR::TypeRef(RawType::USize));
+ rv.write_usize(0, 1);
+ }
+ // - `void *memchr(const void *s, int c, size_t n);`
+ else if( link_name == "memchr" )
+ {
+ auto ptr_alloc = args.at(0).get_relocation(0);
+ auto c = args.at(1).read_i32(0);
+ auto n = args.at(2).read_usize(0);
+ const void* ptr = args.at(0).read_pointer_const(0, n);
+
+ const void* ret = memchr(ptr, c, n);
+
+ rv = Value(::HIR::TypeRef(RawType::USize));
+ rv.create_allocation();
+ if( ret )
+ {
+ rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast<const uint8_t*>(ret) - static_cast<const uint8_t*>(ptr) ));
+ rv.allocation->relocations.push_back({ 0, ptr_alloc });
+ }
+ else
+ {
+ rv.write_usize(0, 0);
+ }
+ }
+ else if( link_name == "memrchr" )
+ {
+ auto ptr_alloc = args.at(0).get_relocation(0);
+ auto c = args.at(1).read_i32(0);
+ auto n = args.at(2).read_usize(0);
+ const void* ptr = args.at(0).read_pointer_const(0, n);
+
+ const void* ret = memrchr(ptr, c, n);
+
+ rv = Value(::HIR::TypeRef(RawType::USize));
+ rv.create_allocation();
+ if( ret )
+ {
+ rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast<const uint8_t*>(ret) - static_cast<const uint8_t*>(ptr) ));
+ rv.allocation->relocations.push_back({ 0, ptr_alloc });
+ }
+ else
+ {
+ rv.write_usize(0, 0);
+ }
+ }
+ else if( link_name == "strlen" )
+ {
+ // strlen - custom implementation to ensure validity
+ bool _is_mut;
+ size_t size;
+ const char* ptr = reinterpret_cast<const char*>( args.at(0).read_pointer_unsafe(0, 1, size, _is_mut) );
+ size_t len = 0;
+ while(size -- && *ptr)
+ {
+ ptr ++;
+ len ++;
+ }
+ args.at(0).read_pointer_const(0, len + 1);
+
+ //rv = Value::new_usize(len);
+ rv = Value(::HIR::TypeRef(RawType::USize));
+ rv.write_usize(0, len);
+ }
+ // Allocators!
+ else
+ {
+ LOG_TODO("Call external function " << link_name);
+ }
+ return true;
+}
+
+bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector<Value> args)
+{
+ TRACE_FUNCTION_R(name, rv);
+ for(const auto& a : args)
+ LOG_DEBUG("#" << (&a - args.data()) << ": " << a);
+ if( name == "type_id" )
+ {
+ const auto& ty_T = ty_params.tys.at(0);
+ static ::std::vector<HIR::TypeRef> type_ids;
+ auto it = ::std::find(type_ids.begin(), type_ids.end(), ty_T);
+ if( it == type_ids.end() )
+ {
+ it = type_ids.insert(it, ty_T);
+ }
+
+ rv = Value::with_size(POINTER_SIZE, false);
+ rv.write_usize(0, it - type_ids.begin());
+ }
+ else if( name == "atomic_fence" || name == "atomic_fence_acq" )
+ {
+ rv = Value();
+ }
+ else if( name == "atomic_store" )
+ {
+ auto& ptr_val = args.at(0);
+ auto& data_val = args.at(1);
+
+ LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_store of a value that isn't a pointer-sized value");
+
+ // There MUST be a relocation at this point with a valid allocation.
+ auto alloc = ptr_val.get_relocation(0);
+ LOG_ASSERT(alloc, "Deref of a value with no relocation");
+
+ // TODO: Atomic side of this?
+ size_t ofs = ptr_val.read_usize(0);
+ alloc.alloc().write_value(ofs, ::std::move(data_val));
+ }
+ else if( name == "atomic_load" || name == "atomic_load_relaxed" )
+ {
+ auto& ptr_val = args.at(0);
+ LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_store of a value that isn't a pointer-sized value");
+
+ // There MUST be a relocation at this point with a valid allocation.
+ auto alloc = ptr_val.get_relocation(0);
+ LOG_ASSERT(alloc, "Deref of a value with no relocation");
+ // TODO: Atomic lock the allocation.
+
+ size_t ofs = ptr_val.read_usize(0);
+ const auto& ty = ty_params.tys.at(0);
+
+ rv = alloc.alloc().read_value(ofs, ty.get_size());
+ }
+ else if( name == "atomic_xadd" || name == "atomic_xadd_relaxed" )
+ {
+ const auto& ty_T = ty_params.tys.at(0);
+ auto ptr_ofs = args.at(0).read_usize(0);
+ auto ptr_alloc = args.at(0).get_relocation(0);
+ auto v = args.at(1).read_value(0, ty_T.get_size());
+
+ // TODO: Atomic lock the allocation.
+ if( !ptr_alloc || !ptr_alloc.is_alloc() ) {
+ LOG_ERROR("atomic pointer has no allocation");
+ }
+
+ // - Result is the original value
+ rv = ptr_alloc.alloc().read_value(ptr_ofs, ty_T.get_size());
+
+ auto val_l = PrimitiveValueVirt::from_value(ty_T, rv);
+ const auto val_r = PrimitiveValueVirt::from_value(ty_T, v);
+ val_l.get().add( val_r.get() );
+
+ val_l.get().write_to_value( ptr_alloc.alloc(), ptr_ofs );
+ }
+ else if( name == "atomic_xsub" || name == "atomic_xsub_relaxed" || name == "atomic_xsub_rel" )
+ {
+ const auto& ty_T = ty_params.tys.at(0);
+ auto ptr_ofs = args.at(0).read_usize(0);
+ auto ptr_alloc = args.at(0).get_relocation(0);
+ auto v = args.at(1).read_value(0, ty_T.get_size());
+
+ // TODO: Atomic lock the allocation.
+ if( !ptr_alloc || !ptr_alloc.is_alloc() ) {
+ LOG_ERROR("atomic pointer has no allocation");
+ }
+
+ // - Result is the original value
+ rv = ptr_alloc.alloc().read_value(ptr_ofs, ty_T.get_size());
+
+ auto val_l = PrimitiveValueVirt::from_value(ty_T, rv);
+ const auto val_r = PrimitiveValueVirt::from_value(ty_T, v);
+ val_l.get().subtract( val_r.get() );
+
+ val_l.get().write_to_value( ptr_alloc.alloc(), ptr_ofs );
+ }
+ else if( name == "atomic_xchg" )
+ {
+ const auto& ty_T = ty_params.tys.at(0);
+ auto data_ref = args.at(0).read_pointer_valref_mut(0, ty_T.get_size());
+ const auto& new_v = args.at(1);
+
+ rv = data_ref.read_value(0, new_v.size());
+ data_ref.m_alloc.alloc().write_value( data_ref.m_offset, new_v );
+ }
+ else if( name == "atomic_cxchg" )
+ {
+ const auto& ty_T = ty_params.tys.at(0);
+ // TODO: Get a ValueRef to the target location
+ auto data_ref = args.at(0).read_pointer_valref_mut(0, ty_T.get_size());
+ const auto& old_v = args.at(1);
+ const auto& new_v = args.at(2);
+ rv = Value::with_size( ty_T.get_size() + 1, false );
+ rv.write_value(0, data_ref.read_value(0, old_v.size()));
+ LOG_DEBUG("> *ptr = " << data_ref);
+ if( data_ref.compare(old_v.data_ptr(), old_v.size()) == true ) {
+ data_ref.m_alloc.alloc().write_value( data_ref.m_offset, new_v );
+ rv.write_u8( old_v.size(), 1 );
+ }
+ else {
+ rv.write_u8( old_v.size(), 0 );
+ }
+ }
+ else if( name == "transmute" )
+ {
+ // Transmute requires the same size, so just copying the value works
+ rv = ::std::move(args.at(0));
+ }
+ else if( name == "assume" )
+ {
+ // Assume is a no-op which returns unit
+ }
+ else if( name == "offset" )
+ {
+ auto ptr_alloc = args.at(0).get_relocation(0);
+ auto ptr_ofs = args.at(0).read_usize(0);
+ auto& ofs_val = args.at(1);
+
+ auto delta_counts = ofs_val.read_usize(0);
+ auto new_ofs = ptr_ofs + delta_counts * ty_params.tys.at(0).get_size();
+ if(POINTER_SIZE != 8) {
+ new_ofs &= 0xFFFFFFFF;
+ }
+
+ rv = ::std::move(args.at(0));
+ rv.write_usize(0, new_ofs);
+ if( ptr_alloc ) {
+ rv.allocation->relocations.push_back({ 0, ptr_alloc });
+ }
+ }
+ // effectively ptr::write
+ else if( name == "move_val_init" )
+ {
+ auto& ptr_val = args.at(0);
+ auto& data_val = args.at(1);
+
+ LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "move_val_init of an address that isn't a pointer-sized value");
+
+ // There MUST be a relocation at this point with a valid allocation.
+ LOG_ASSERT(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)");
+ LOG_TRACE("Deref " << ptr_val << " and store " << data_val);
+
+ auto ptr_alloc = ptr_val.get_relocation(0);
+ LOG_ASSERT(ptr_alloc, "Deref of a value with no relocation");
+
+ size_t ofs = ptr_val.read_usize(0);
+ ptr_alloc.alloc().write_value(ofs, ::std::move(data_val));
+ LOG_DEBUG(ptr_alloc.alloc());
+ }
+ else if( name == "uninit" )
+ {
+ rv = Value(ty_params.tys.at(0));
+ }
+ else if( name == "init" )
+ {
+ rv = Value(ty_params.tys.at(0));
+ rv.mark_bytes_valid(0, rv.size());
+ }
+ // - Unsized stuff
+ else if( name == "size_of_val" )
+ {
+ auto& val = args.at(0);
+ const auto& ty = ty_params.tys.at(0);
+ rv = Value(::HIR::TypeRef(RawType::USize));
+ // Get unsized type somehow.
+ // - _HAS_ to be the last type, so that makes it easier
+ size_t fixed_size = 0;
+ if( const auto* ity = ty.get_unsized_type(fixed_size) )
+ {
+ const auto meta_ty = ty.get_meta_type();
+ LOG_DEBUG("size_of_val - " << ty << " ity=" << *ity << " meta_ty=" << meta_ty << " fixed_size=" << fixed_size);
+ size_t flex_size = 0;
+ if( const auto* w = ity->get_wrapper() )
+ {
+ LOG_ASSERT(w->type == TypeWrapper::Ty::Slice, "size_of_val on wrapped type that isn't a slice - " << *ity);
+ size_t item_size = ity->get_inner().get_size();
+ size_t item_count = val.read_usize(POINTER_SIZE);
+ flex_size = item_count * item_size;
+ LOG_DEBUG("> item_size=" << item_size << " item_count=" << item_count << " flex_size=" << flex_size);
+ }
+ else if( ity->inner_type == RawType::Str )
+ {
+ flex_size = val.read_usize(POINTER_SIZE);
+ }
+ else if( ity->inner_type == RawType::TraitObject )
+ {
+ LOG_TODO("size_of_val - Trait Object - " << ty);
+ }
+ else
+ {
+ LOG_BUG("Inner unsized type unknown - " << *ity);
+ }
+
+ rv.write_usize(0, fixed_size + flex_size);
+ }
+ else
+ {
+ rv.write_usize(0, ty.get_size());
+ }
+ }
+ else if( name == "drop_in_place" )
+ {
+ auto& val = args.at(0);
+ const auto& ty = ty_params.tys.at(0);
+ return drop_value(val, ty);
+ }
+ // ----------------------------------------------------------------
+ // Checked arithmatic
+ else if( name == "add_with_overflow" )
+ {
+ const auto& ty = ty_params.tys.at(0);
+
+ auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
+ auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
+ bool didnt_overflow = lhs.get().add( rhs.get() );
+
+ // Get return type - a tuple of `(T, bool,)`
+ ::HIR::GenericPath gp;
+ gp.m_params.tys.push_back(ty);
+ gp.m_params.tys.push_back(::HIR::TypeRef { RawType::Bool });
+ const auto& dty = m_modtree.get_composite(gp);
+
+ rv = Value(::HIR::TypeRef(&dty));
+ lhs.get().write_to_value(rv, dty.fields[0].first);
+ rv.write_u8( dty.fields[1].first, didnt_overflow ? 0 : 1 ); // Returns true if overflow happened
+ }
+ else if( name == "sub_with_overflow" )
+ {
+ const auto& ty = ty_params.tys.at(0);
+
+ auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
+ auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
+ bool didnt_overflow = lhs.get().subtract( rhs.get() );
+
+ // Get return type - a tuple of `(T, bool,)`
+ ::HIR::GenericPath gp;
+ gp.m_params.tys.push_back(ty);
+ gp.m_params.tys.push_back(::HIR::TypeRef { RawType::Bool });
+ const auto& dty = m_modtree.get_composite(gp);
+
+ rv = Value(::HIR::TypeRef(&dty));
+ lhs.get().write_to_value(rv, dty.fields[0].first);
+ rv.write_u8( dty.fields[1].first, didnt_overflow ? 0 : 1 ); // Returns true if overflow happened
+ }
+ else if( name == "mul_with_overflow" )
+ {
+ const auto& ty = ty_params.tys.at(0);
+
+ auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
+ auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
+ bool didnt_overflow = lhs.get().multiply( rhs.get() );
+
+ // Get return type - a tuple of `(T, bool,)`
+ ::HIR::GenericPath gp;
+ gp.m_params.tys.push_back(ty);
+ gp.m_params.tys.push_back(::HIR::TypeRef { RawType::Bool });
+ const auto& dty = m_modtree.get_composite(gp);
+
+ rv = Value(::HIR::TypeRef(&dty));
+ lhs.get().write_to_value(rv, dty.fields[0].first);
+ rv.write_u8( dty.fields[1].first, didnt_overflow ? 0 : 1 ); // Returns true if overflow happened
+ }
+ // Overflowing artithmatic
+ else if( name == "overflowing_sub" )
+ {
+ const auto& ty = ty_params.tys.at(0);
+
+ auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
+ auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
+ lhs.get().subtract( rhs.get() );
+
+ rv = Value(ty);
+ lhs.get().write_to_value(rv, 0);
+ }
+ // ----------------------------------------------------------------
+ // memcpy
+ else if( name == "copy_nonoverlapping" )
+ {
+ auto src_ofs = args.at(0).read_usize(0);
+ auto src_alloc = args.at(0).get_relocation(0);
+ auto dst_ofs = args.at(1).read_usize(0);
+ auto dst_alloc = args.at(1).get_relocation(0);
+ size_t ent_count = args.at(2).read_usize(0);
+ size_t ent_size = ty_params.tys.at(0).get_size();
+ auto byte_count = ent_count * ent_size;
+
+ LOG_ASSERT(src_alloc, "Source of copy* must have an allocation");
+ LOG_ASSERT(dst_alloc, "Destination of copy* must be a memory allocation");
+ LOG_ASSERT(dst_alloc.is_alloc(), "Destination of copy* must be a memory allocation");
+
+ switch(src_alloc.get_ty())
+ {
+ case RelocationPtr::Ty::Allocation: {
+ auto v = src_alloc.alloc().read_value(src_ofs, byte_count);
+ LOG_DEBUG("v = " << v);
+ dst_alloc.alloc().write_value(dst_ofs, ::std::move(v));
+ } break;
+ case RelocationPtr::Ty::StdString:
+ LOG_ASSERT(src_ofs <= src_alloc.str().size(), "");
+ LOG_ASSERT(byte_count <= src_alloc.str().size(), "");
+ LOG_ASSERT(src_ofs + byte_count <= src_alloc.str().size(), "");
+ dst_alloc.alloc().write_bytes(dst_ofs, src_alloc.str().data() + src_ofs, byte_count);
+ break;
+ case RelocationPtr::Ty::Function:
+ LOG_FATAL("Attempt to copy* a function");
+ break;
+ case RelocationPtr::Ty::FfiPointer:
+ LOG_ASSERT(src_ofs <= src_alloc.ffi().size, "");
+ LOG_ASSERT(byte_count <= src_alloc.ffi().size, "");
+ LOG_ASSERT(src_ofs + byte_count <= src_alloc.ffi().size, "");
+ dst_alloc.alloc().write_bytes(dst_ofs, src_alloc.ffi().ptr_value + src_ofs, byte_count);
+ break;
+ }
+ }
+ else
+ {
+ LOG_TODO("Call intrinsic \"" << name << "\"");
+ }
+ return true;
+}
+
+// TODO: Use a ValueRef instead?
+bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow/*=false*/)
+{
+ // TODO: After the drop is done, flag the backing allocation for `ptr` as freed
+ if( is_shallow )
+ {
+ // HACK: Only works for Box<T> where the first pointer is the data pointer
+ auto box_ptr_vr = ptr.read_pointer_valref_mut(0, POINTER_SIZE);
+ auto ofs = box_ptr_vr.read_usize(0);
+ auto alloc = box_ptr_vr.get_relocation(0);
+ if( ofs != 0 || !alloc || !alloc.is_alloc() ) {
+ LOG_ERROR("Attempting to shallow drop with invalid pointer (no relocation or non-zero offset) - " << box_ptr_vr);
+ }
+
+ LOG_DEBUG("drop_value SHALLOW deallocate " << alloc);
+ alloc.alloc().mark_as_freed();
+ return true;
+ }
+ if( const auto* w = ty.get_wrapper() )
+ {
+ switch( w->type )
+ {
+ case TypeWrapper::Ty::Borrow:
+ if( w->size == static_cast<size_t>(::HIR::BorrowType::Move) )
+ {
+ LOG_TODO("Drop - " << ty << " - dereference and go to inner");
+ // TODO: Clear validity on the entire inner value.
+ //auto iptr = ptr.read_value(0, ty.get_size());
+ //drop_value(iptr, ty.get_inner());
+ }
+ else
+ {
+ // No destructor
+ }
+ break;
+ case TypeWrapper::Ty::Pointer:
+ // No destructor
+ break;
+ case TypeWrapper::Ty::Slice: {
+ // - Get thin pointer and count
+ auto ofs = ptr.read_usize(0);
+ auto ptr_reloc = ptr.get_relocation(0);
+ auto count = ptr.read_usize(POINTER_SIZE);
+
+ auto ity = ty.get_inner();
+ auto pty = ity.wrapped(TypeWrapper::Ty::Borrow, static_cast<size_t>(::HIR::BorrowType::Move));
+ for(uint64_t i = 0; i < count; i ++)
+ {
+ auto ptr = Value::new_pointer(pty, ofs, ptr_reloc);
+ if( !drop_value(ptr, ity) ) {
+ LOG_TODO("Handle closure looping when dropping a slice");
+ }
+ ofs += ity.get_size();
+ }
+ } break;
+ // TODO: Arrays?
+ default:
+ LOG_TODO("Drop - " << ty << " - array?");
+ break;
+ }
+ }
+ else
+ {
+ if( ty.inner_type == RawType::Composite )
+ {
+ if( ty.composite_type->drop_glue != ::HIR::Path() )
+ {
+ LOG_DEBUG("Drop - " << ty);
+
+ Value tmp;
+ return this->call_path(tmp, ty.composite_type->drop_glue, { ptr });
+ }
+ else
+ {
+ // No drop glue
+ }
+ }
+ else if( ty.inner_type == RawType::TraitObject )
+ {
+ LOG_TODO("Drop - " << ty << " - trait object");
+ }
+ else
+ {
+ // No destructor
+ }
+ }
+ return true;
+}
diff --git a/tools/standalone_miri/miri.hpp b/tools/standalone_miri/miri.hpp
new file mode 100644
index 00000000..09d92a9b
--- /dev/null
+++ b/tools/standalone_miri/miri.hpp
@@ -0,0 +1,79 @@
+
+#pragma once
+#include "module_tree.hpp"
+#include "value.hpp"
+
+struct ThreadState
+{
+ static unsigned s_next_tls_key;
+ unsigned call_stack_depth;
+ ::std::vector<uint64_t> tls_values;
+
+ ThreadState():
+ call_stack_depth(0)
+ {
+ }
+
+ struct DecOnDrop {
+ unsigned* p;
+ ~DecOnDrop() { (*p) --; }
+ };
+ DecOnDrop enter_function() {
+ this->call_stack_depth ++;
+ return DecOnDrop { &this->call_stack_depth };
+ }
+};
+
+class InterpreterThread
+{
+ friend struct MirHelpers;
+ struct StackFrame
+ {
+ ::std::function<bool(Value&,Value)> cb;
+ const Function& fcn;
+ Value ret;
+ ::std::vector<Value> args;
+ ::std::vector<Value> locals;
+ ::std::vector<bool> drop_flags;
+
+ unsigned bb_idx;
+ unsigned stmt_idx;
+
+ StackFrame(const Function& fcn, ::std::vector<Value> args);
+ static StackFrame make_wrapper(::std::function<bool(Value&,Value)> cb) {
+ static Function f;
+ StackFrame rv(f, {});
+ rv.cb = ::std::move(cb);
+ return rv;
+ }
+ };
+
+ ModuleTree& m_modtree;
+ ThreadState m_thread;
+ ::std::vector<StackFrame> m_stack;
+
+public:
+ InterpreterThread(ModuleTree& modtree):
+ m_modtree(modtree)
+ {
+ }
+ ~InterpreterThread();
+
+ void start(const ::HIR::Path& p, ::std::vector<Value> args);
+ // Returns `true` if the call stack empties
+ bool step_one(Value& out_thread_result);
+
+private:
+ bool pop_stack(Value& out_thread_result);
+
+ // Returns true if the call was resolved instantly
+ bool call_path(Value& ret_val, const ::HIR::Path& p, ::std::vector<Value> args);
+ // Returns true if the call was resolved instantly
+ bool call_extern(Value& ret_val, const ::std::string& name, const ::std::string& abi, ::std::vector<Value> args);
+ // Returns true if the call was resolved instantly
+ bool call_intrinsic(Value& ret_val, const ::std::string& name, const ::HIR::PathParams& pp, ::std::vector<Value> args);
+
+ // Returns true if the call was resolved instantly
+ bool drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow=false);
+};
+
diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp
index 2513140a..8beba018 100644
--- a/tools/standalone_miri/module_tree.cpp
+++ b/tools/standalone_miri/module_tree.cpp
@@ -5,6 +5,7 @@
#include "lex.hpp"
#include "value.hpp"
#include <iostream>
+#include <algorithm> // std::find
#include "debug.hpp"
ModuleTree::ModuleTree()
@@ -31,18 +32,19 @@ struct Parser
RawType parse_core_type();
::HIR::TypeRef parse_type();
::HIR::GenericPath parse_tuple();
+
+ const DataType* get_composite(::HIR::GenericPath gp);
};
void ModuleTree::load_file(const ::std::string& path)
{
if( !loaded_files.insert(path).second )
{
- ::std::cout << "DEBUG: load_file(" << path << ") - Already loaded" << ::std::endl;
+ LOG_DEBUG("load_file(" << path << ") - Already loaded");
return ;
}
- ::std::cout << "DEBUG: load_file(" << path << ")" << ::std::endl;
- //TRACE_FUNCTION_F(path);
+ TRACE_FUNCTION_R(path, "");
auto parse = Parser { *this, path };
while(parse.parse_one())
@@ -53,8 +55,8 @@ void ModuleTree::load_file(const ::std::string& path)
// Parse a single item from a .mir file
bool Parser::parse_one()
{
- //::std::cout << "DEBUG: parse_one" << ::std::endl;
- if( lex.next() == "" ) // EOF?
+ //TRACE_FUNCTION_F("");
+ if( lex.next() == TokenClass::Eof )
{
return false;
}
@@ -65,7 +67,7 @@ bool Parser::parse_one()
lex.check(TokenClass::String);
auto path = ::std::move(lex.next().strval);
lex.consume();
- //::std::cout << "DEBUG: parse_one - crate '" << path << "'" << ::std::endl;
+ //LOG_TRACE(lex << "crate '" << path << "'");
lex.check_consume(';');
@@ -75,7 +77,7 @@ bool Parser::parse_one()
else if( lex.consume_if("fn") )
{
auto p = parse_path();
- //::std::cout << "DEBUG: parse_one - fn " << p << ::std::endl;
+ //LOG_TRACE(lex << "fn " << p);
lex.check_consume('(');
::std::vector<::HIR::TypeRef> arg_tys;
@@ -91,7 +93,7 @@ bool Parser::parse_one()
{
rv_ty = parse_type();
}
-
+
if( lex.consume_if('=') )
{
auto link_name = ::std::move(lex.check_consume(TokenClass::String).strval);
@@ -99,6 +101,7 @@ bool Parser::parse_one()
auto abi = ::std::move(lex.check_consume(TokenClass::String).strval);
lex.check_consume(';');
+ LOG_DEBUG(lex << "extern fn " << p);
auto p2 = p;
tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, {link_name, abi}, {} }) );
}
@@ -106,6 +109,7 @@ bool Parser::parse_one()
{
auto body = parse_body();
+ LOG_DEBUG(lex << "fn " << p);
auto p2 = p;
tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, {}, ::std::move(body) }) );
}
@@ -113,13 +117,22 @@ bool Parser::parse_one()
else if( lex.consume_if("static") )
{
auto p = parse_path();
- //::std::cout << "DEBUG: parse_one - static " << p << ::std::endl;
+ //LOG_TRACE(lex << "static " << p);
lex.check_consume(':');
auto ty = parse_type();
// TODO: externs?
lex.check_consume('=');
lex.check(TokenClass::String);
auto data = ::std::move(lex.consume().strval);
+
+ Static s;
+ s.val = Value(ty);
+ // - Statics need to always have an allocation (for references)
+ if( !s.val.allocation )
+ s.val.create_allocation();
+ s.val.write_bytes(0, data.data(), data.size());
+ s.ty = ty;
+
if( lex.consume_if('{') )
{
while( !lex.consume_if('}') )
@@ -134,15 +147,20 @@ bool Parser::parse_one()
if( lex.next() == TokenClass::String )
{
auto reloc_str = ::std::move(lex.consume().strval);
- // TODO: Add relocation
+
+ auto a = Allocation::new_alloc( reloc_str.size() );
+ //a.alloc().set_tag();
+ a->write_bytes(0, reloc_str.data(), reloc_str.size());
+ s.val.allocation->relocations.push_back({ ofs, /*size,*/ RelocationPtr::new_alloc(::std::move(a)) });
}
- else if( lex.next() == "::" )
+ else if( lex.next() == "::" || lex.next() == "<" )
{
auto reloc_path = parse_path();
- // TODO: Add relocation
+ s.val.allocation->relocations.push_back({ ofs, /*size,*/ RelocationPtr::new_fcn(reloc_path) });
}
else
{
+ LOG_FATAL(lex << "Unexepcted token " << lex.next() << " in relocation value");
throw "ERROR";
}
if( ! lex.consume_if(',') ) {
@@ -153,15 +171,13 @@ bool Parser::parse_one()
}
lex.check_consume(';');
- Value val = Value(ty);
- val.write_bytes(0, data.data(), data.size());
-
- tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(val) ));
+ LOG_DEBUG(lex << "static " << p);
+ tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(s) ));
}
else if( lex.consume_if("type") )
{
auto p = (lex.consume_if('(')) ? parse_tuple() : parse_genericpath();
- //::std::cout << "DEBUG: parse_one - type " << p << ::std::endl;
+ //LOG_TRACE("type " << p);
auto rv = DataType {};
rv.my_path = p;
@@ -206,7 +222,7 @@ bool Parser::parse_one()
lex.check_consume('=');
auto ty = parse_type();
lex.check_consume(';');
- //::std::cout << ofs << " " << ty << ::std::endl;
+ //LOG_DEBUG(ofs << " " << ty);
rv.fields.push_back(::std::make_pair(ofs, ::std::move(ty)));
}
@@ -250,7 +266,7 @@ bool Parser::parse_one()
//const auto* tag_ty = &rv.fields.at(base_idx).second;
//for(auto idx : other_idx)
//{
- // assert(tag_ty->wrappers.size() == 0);
+ // assert(tag_ty->get_wrapper() == nullptr);
// assert(tag_ty->inner_type == RawType::Composite);
// LOG_TODO(lex << "Calculate tag offset with nested tag - " << idx << " ty=" << *tag_ty);
//}
@@ -272,10 +288,10 @@ bool Parser::parse_one()
if( rv.alignment == 0 && rv.fields.size() != 0 )
{
- ::std::cerr << lex << "Alignment of zero with fields is invalid, " << p << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Alignment of zero with fields is invalid, " << p);
}
+ LOG_DEBUG(lex << "type " << p);
auto it = this->tree.data_types.find(p);
if( it != this->tree.data_types.end() )
{
@@ -285,10 +301,7 @@ bool Parser::parse_one()
}
else
{
- //::std::cerr << lex << "Duplicate definition of " << p << ::std::endl;
-
- // Not really an error, can happen when loading crates
- //throw "ERROR";
+ //LOG_ERROR(lex << "Duplicate definition of " << p);
}
}
else
@@ -298,7 +311,7 @@ bool Parser::parse_one()
}
else
{
- ::std::cerr << lex << "Unexpected token at root - " << lex.next() << ::std::endl;
+ LOG_ERROR(lex << "Unexpected token at root - " << lex.next());
// Unknown item type
throw "ERROR";
@@ -342,8 +355,7 @@ bool Parser::parse_one()
lv = ::MIR::LValue::make_Argument({ idx });
}
catch(const ::std::exception& e) {
- ::std::cerr << lex << "Invalid argument name - " << name << " - " << e.what() << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Invalid argument name - " << name << " - " << e.what());
}
}
// Hard-coded "RETURN" lvalue
@@ -354,8 +366,7 @@ bool Parser::parse_one()
else {
auto it = ::std::find(var_names.begin(), var_names.end(), name);
if( it == var_names.end() ) {
- ::std::cerr << lex << "Cannot find variable named '" << name << "'" << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Cannot find variable named '" << name << "'");
}
lv = ::MIR::LValue::make_Local(static_cast<unsigned>(it - var_names.begin()));
}
@@ -366,8 +377,7 @@ bool Parser::parse_one()
lv = ::MIR::LValue( ::std::move(path) );
}
else {
- ::std::cerr << lex << "Unexpected token in LValue - " << lex.next() << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unexpected token in LValue - " << lex.next());
}
for(;;)
{
@@ -437,8 +447,7 @@ bool Parser::parse_one()
}
else
{
- ::std::cerr << p.lex << "Expected an integer or float, got " << p.lex.next() << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(p.lex << "Expected an integer or float, got " << p.lex.next());
}
}
else if( p.lex.consume_if("true") ) {
@@ -453,8 +462,7 @@ bool Parser::parse_one()
return ::MIR::Constant::make_ItemAddr({ ::std::move(path) });
}
else {
- ::std::cerr << p.lex << "BUG? " << p.lex.next() << ::std::endl;
- throw "ERROR";
+ LOG_BUG(p.lex << "BUG? " << p.lex.next());
}
}
@@ -635,8 +643,7 @@ bool Parser::parse_one()
op = ::MIR::eUniOp::NEG;
}
else {
- ::std::cerr << lex << "Unexpected token in uniop - " << lex.next() << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unexpected token in uniop - " << lex.next());
}
auto lv = H::parse_lvalue(*this, var_names);
@@ -661,7 +668,7 @@ bool Parser::parse_one()
case '<':
if( t.strval[1] == '<' )
op = ::MIR::eBinOp::BIT_SHL;
- else if( lex.consume_if('=') )
+ else if( t.strval[1] == '=' )
op = ::MIR::eBinOp::LE;
else
op = ::MIR::eBinOp::LT;
@@ -683,8 +690,7 @@ bool Parser::parse_one()
lex.check_consume('=');
break;
default:
- ::std::cerr << lex << "Unexpected token " << t << " in BINOP" << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unexpected token " << t << " in BINOP");
}
auto lv2 = H::parse_param(*this, var_names);
@@ -705,8 +711,7 @@ bool Parser::parse_one()
src_rval = ::MIR::RValue::make_DstMeta({ ::std::move(lv) });
}
else {
- ::std::cerr << lex << "Unexpected token in RValue - " << lex.next() << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unexpected token in RValue - " << lex.next());
}
stmts.push_back(::MIR::Statement::make_Assign({ ::std::move(dst_val), ::std::move(src_rval) }));
@@ -717,8 +722,7 @@ bool Parser::parse_one()
auto name = ::std::move(lex.consume().strval);
auto df_it = ::std::find(drop_flag_names.begin(), drop_flag_names.end(), name);
if( df_it == drop_flag_names.end() ) {
- ::std::cerr << lex << "Unable to find drop flag '" << name << "'" << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unable to find drop flag '" << name << "'");
}
auto df_idx = static_cast<unsigned>( df_it - drop_flag_names.begin() );
lex.check_consume('=');
@@ -736,8 +740,7 @@ bool Parser::parse_one()
auto name = ::std::move(lex.consume().strval);
df_it = ::std::find(drop_flag_names.begin(), drop_flag_names.end(), name);
if( df_it == drop_flag_names.end() ) {
- ::std::cerr << lex << "Unable to find drop flag '" << name << "'" << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unable to find drop flag '" << name << "'");
}
auto other_idx = static_cast<unsigned>( df_it - drop_flag_names.begin() );
@@ -759,8 +762,7 @@ bool Parser::parse_one()
auto name = ::std::move(lex.consume().strval);
auto df_it = ::std::find(drop_flag_names.begin(), drop_flag_names.end(), name);
if( df_it == drop_flag_names.end() ) {
- ::std::cerr << lex << "Unable to find drop flag '" << name << "'" << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unable to find drop flag '" << name << "'");
}
flag_idx = static_cast<unsigned>( df_it - drop_flag_names.begin() );
}
@@ -824,7 +826,7 @@ bool Parser::parse_one()
break;
}
lex.check_consume(';');
- //::std::cout << stmts.back() << ::std::endl;
+ //LOG_TRACE(stmts.back());
}
lex.check(TokenClass::Ident);
@@ -910,8 +912,7 @@ bool Parser::parse_one()
vals = ::MIR::SwitchValues::make_String(::std::move(values));
}
else {
- ::std::cerr << lex << "Unexpected token for SWITCHVALUE value - " << lex.next() << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unexpected token for SWITCHVALUE value - " << lex.next());
}
lex.check_consume('_');
lex.check_consume('=');
@@ -958,8 +959,7 @@ bool Parser::parse_one()
}
else
{
- ::std::cerr << lex << "Unexpected token at terminator - " << lex.next() << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unexpected token at terminator - " << lex.next());
}
lex.check_consume('}');
@@ -1050,7 +1050,7 @@ bool Parser::parse_one()
}
RawType Parser::parse_core_type()
{
- //::std::cout << lex.next() << ::std::endl;
+ //LOG_TRACE(lex.next());
lex.check(TokenClass::Ident);
auto tok = lex.consume();
// Primitive type.
@@ -1106,8 +1106,7 @@ RawType Parser::parse_core_type()
return RawType::Str;
}
else {
- ::std::cerr << lex << "Unknown core type " << tok << "'" << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unknown core type " << tok << "'");
}
}
::HIR::TypeRef Parser::parse_type()
@@ -1121,19 +1120,8 @@ RawType Parser::parse_core_type()
// Tuples! Should point to a composite
::HIR::GenericPath gp = parse_tuple();
- // Look up this type, then create a TypeRef referring to the type in the datastore
- // - May need to create an unpopulated type?
- auto it = tree.data_types.find(gp);
- if( it == tree.data_types.end() )
- {
- // TODO: Later on need to check if the type is valid.
- auto v = ::std::make_unique<DataType>(DataType {});
- v->my_path = gp;
- auto ir = tree.data_types.insert(::std::make_pair( ::std::move(gp), ::std::move(v)) );
- it = ir.first;
- }
// Good.
- return ::HIR::TypeRef(it->second.get());
+ return ::HIR::TypeRef( this->get_composite(::std::move(gp)) );
}
else if( lex.consume_if('[') )
{
@@ -1142,15 +1130,14 @@ RawType Parser::parse_core_type()
{
size_t size = lex.next().integer();
lex.consume();
- rv.wrappers.insert( rv.wrappers.begin(), { TypeWrapper::Ty::Array, size });
+ lex.check_consume(']');
+ return ::std::move(rv).wrap( TypeWrapper::Ty::Array, size );
}
else
{
- // TODO: How to handle arrays?
- rv.wrappers.insert( rv.wrappers.begin(), { TypeWrapper::Ty::Slice, 0 });
+ lex.check_consume(']');
+ return ::std::move(rv).wrap( TypeWrapper::Ty::Slice, 0 );
}
- lex.check_consume(']');
- return rv;
}
else if( lex.consume_if('!') )
{
@@ -1158,6 +1145,11 @@ RawType Parser::parse_core_type()
}
else if( lex.consume_if('&') )
{
+ if( lex.next() == TokenClass::Lifetime )
+ {
+ // TODO: Handle lifetime names (require them?)
+ lex.consume();
+ }
auto bt = ::HIR::BorrowType::Shared;
if( lex.consume_if("move") )
bt = ::HIR::BorrowType::Move;
@@ -1165,9 +1157,7 @@ RawType Parser::parse_core_type()
bt = ::HIR::BorrowType::Unique;
else
; // keep as shared
- auto rv = parse_type();
- rv.wrappers.insert( rv.wrappers.begin(), { TypeWrapper::Ty::Borrow, static_cast<size_t>(bt) });
- return rv;
+ return parse_type().wrap( TypeWrapper::Ty::Borrow, static_cast<size_t>(bt) );
}
else if( lex.consume_if('*') )
{
@@ -1180,26 +1170,12 @@ RawType Parser::parse_core_type()
; // keep as shared
else
throw "ERROR";
- auto rv = parse_type();
- rv.wrappers.insert( rv.wrappers.begin(), { TypeWrapper::Ty::Pointer, static_cast<size_t>(bt) });
- return rv;
+ return parse_type().wrap( TypeWrapper::Ty::Pointer, static_cast<size_t>(bt) );
}
else if( lex.next() == "::" )
{
auto path = parse_genericpath();
- // Look up this type, then create a TypeRef referring to the type in the datastore
- // - May need to create an unpopulated type?
- auto it = tree.data_types.find(path);
- if( it == tree.data_types.end() )
- {
- // TODO: Later on need to check if the type is valid.
- auto v = ::std::make_unique<DataType>(DataType {});
- v->my_path = path;
- auto ir = tree.data_types.insert(::std::make_pair( ::std::move(path), ::std::move(v)) );
- it = ir.first;
- }
- // Good.
- return ::HIR::TypeRef(it->second.get());
+ return ::HIR::TypeRef( this->get_composite(::std::move(path)));
}
else if( lex.next() == "extern" || lex.next() == "fn" || lex.next() == "unsafe" )
{
@@ -1269,12 +1245,28 @@ RawType Parser::parse_core_type()
::std::vector<::HIR::GenericPath> markers;
while(lex.consume_if('+'))
{
- // TODO: Detect/parse lifetimes?
- markers.push_back(parse_genericpath());
+ if( lex.next() == TokenClass::Lifetime )
+ {
+ // TODO: Include lifetimes in output?
+ lex.consume();
+ }
+ else
+ {
+ markers.push_back(parse_genericpath());
+ }
}
lex.consume_if(')');
- return ::HIR::TypeRef(RawType::TraitObject);
- // TODO: Generate the vtable path and locate that struct
+
+ auto rv = ::HIR::TypeRef(RawType::TraitObject);
+ if( base_trait != ::HIR::GenericPath() )
+ {
+ // Generate vtable path
+ auto vtable_path = base_trait;
+ vtable_path.m_simplepath.ents.back() += "#vtable";
+ // - TODO: Associated types?
+ rv.composite_type = this->get_composite( ::std::move(vtable_path) );
+ }
+ return rv;
}
else if( lex.next() == TokenClass::Ident )
{
@@ -1282,10 +1274,22 @@ RawType Parser::parse_core_type()
}
else
{
- ::std::cerr << lex << "Unexpected token in type - " << lex.next() << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(lex << "Unexpected token in type - " << lex.next());
}
}
+const DataType* Parser::get_composite(::HIR::GenericPath gp)
+{
+ auto it = tree.data_types.find(gp);
+ if( it == tree.data_types.end() )
+ {
+ // TODO: Later on need to check if the type is valid.
+ auto v = ::std::make_unique<DataType>(DataType {});
+ v->my_path = gp;
+ auto ir = tree.data_types.insert(::std::make_pair( ::std::move(gp), ::std::move(v)) );
+ it = ir.first;
+ }
+ return it->second.get();
+}
::HIR::SimplePath ModuleTree::find_lang_item(const char* name) const
{
@@ -1296,8 +1300,7 @@ const Function& ModuleTree::get_function(const ::HIR::Path& p) const
auto it = functions.find(p);
if(it == functions.end())
{
- ::std::cerr << "Unable to find function " << p << " for invoke" << ::std::endl;
- throw "";
+ LOG_ERROR("Unable to find function " << p << " for invoke");
}
return it->second;
}
@@ -1310,17 +1313,16 @@ const Function* ModuleTree::get_function_opt(const ::HIR::Path& p) const
}
return &it->second;
}
-Value& ModuleTree::get_static(const ::HIR::Path& p)
+Static& ModuleTree::get_static(const ::HIR::Path& p)
{
auto it = statics.find(p);
if(it == statics.end())
{
- ::std::cerr << "Unable to find static " << p << " for invoke" << ::std::endl;
- throw "";
+ LOG_ERROR("Unable to find static " << p << " for invoke");
}
return it->second;
}
-Value* ModuleTree::get_static_opt(const ::HIR::Path& p)
+Static* ModuleTree::get_static_opt(const ::HIR::Path& p)
{
auto it = statics.find(p);
if(it == statics.end())
@@ -1328,4 +1330,4 @@ Value* ModuleTree::get_static_opt(const ::HIR::Path& p)
return nullptr;
}
return &it->second;
-} \ No newline at end of file
+}
diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp
index ca24b06a..5479d9ef 100644
--- a/tools/standalone_miri/module_tree.hpp
+++ b/tools/standalone_miri/module_tree.hpp
@@ -9,15 +9,14 @@
#include "../../src/mir/mir.hpp"
#include "hir_sim.hpp"
-
-struct Value;
+#include "value.hpp"
struct Function
{
::HIR::Path my_path;
::std::vector<::HIR::TypeRef> args;
::HIR::TypeRef ret_ty;
-
+
// If `link_name` is non-empty, then the function is an external
struct {
::std::string link_name;
@@ -25,6 +24,11 @@ struct Function
} external;
::MIR::Function m_mir;
};
+struct Static
+{
+ ::HIR::TypeRef ty;
+ Value val;
+};
/// Container for loaded code and structures
class ModuleTree
@@ -34,8 +38,7 @@ class ModuleTree
::std::set<::std::string> loaded_files;
::std::map<::HIR::Path, Function> functions;
- ::std::map<::HIR::Path, Value> statics;
- // TODO: statics
+ ::std::map<::HIR::Path, Static> statics;
// Hack: Tuples are stored as `::""::<A,B,C,...>`
::std::map<::HIR::GenericPath, ::std::unique_ptr<DataType>> data_types;
@@ -47,8 +50,8 @@ public:
::HIR::SimplePath find_lang_item(const char* name) const;
const Function& get_function(const ::HIR::Path& p) const;
const Function* get_function_opt(const ::HIR::Path& p) const;
- Value& get_static(const ::HIR::Path& p);
- Value* get_static_opt(const ::HIR::Path& p);
+ Static& get_static(const ::HIR::Path& p);
+ Static* get_static_opt(const ::HIR::Path& p);
const DataType& get_composite(const ::HIR::GenericPath& p) const {
return *data_types.at(p);
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index beff8a38..cf378077 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -1,6 +1,10 @@
-//
-//
-//
+/*
+ * mrustc Standalone MIRI
+ * - by John Hodge (Mutabah)
+ *
+ * value.cpp
+ * - Runtime values
+ */
#include "value.hpp"
#include "hir_sim.hpp"
#include "module_tree.hpp"
@@ -9,49 +13,79 @@
#include <algorithm>
#include "debug.hpp"
-AllocationPtr Allocation::new_alloc(size_t size)
+AllocationHandle Allocation::new_alloc(size_t size)
{
Allocation* rv = new Allocation();
rv->refcount = 1;
rv->data.resize( (size + 8-1) / 8 ); // QWORDS
rv->mask.resize( (size + 8-1) / 8 ); // bitmap bytes
//LOG_DEBUG(rv << " ALLOC");
- return AllocationPtr(rv);
+ return AllocationHandle(rv);
}
-AllocationPtr AllocationPtr::new_fcn(::HIR::Path p)
+AllocationHandle::AllocationHandle(const AllocationHandle& x):
+ m_ptr(x.m_ptr)
{
- AllocationPtr rv;
+ if( m_ptr )
+ {
+ assert(m_ptr->refcount != 0);
+ assert(m_ptr->refcount != SIZE_MAX);
+ m_ptr->refcount += 1;
+ //LOG_DEBUG(m_ptr << " REF++ " << m_ptr->refcount);
+ }
+}
+AllocationHandle::~AllocationHandle()
+{
+ if( m_ptr )
+ {
+ m_ptr->refcount -= 1;
+ //LOG_DEBUG(m_ptr << " REF-- " << m_ptr->refcount);
+ if(m_ptr->refcount == 0)
+ {
+ delete m_ptr;
+ }
+ }
+}
+
+RelocationPtr RelocationPtr::new_alloc(AllocationHandle alloc)
+{
+ RelocationPtr rv;
+ auto* ptr = alloc.m_ptr;
+ alloc.m_ptr = nullptr;
+ rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::Allocation) );
+ return rv;
+}
+RelocationPtr RelocationPtr::new_fcn(::HIR::Path p)
+{
+ RelocationPtr rv;
auto* ptr = new ::HIR::Path(::std::move(p));
rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::Function) );
return rv;
}
-AllocationPtr AllocationPtr::new_string(const ::std::string* ptr)
+RelocationPtr RelocationPtr::new_string(const ::std::string* ptr)
{
- AllocationPtr rv;
+ RelocationPtr rv;
rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::StdString) );
return rv;
}
-AllocationPtr AllocationPtr::new_ffi(FFIPointer info)
+RelocationPtr RelocationPtr::new_ffi(FFIPointer info)
{
- AllocationPtr rv;
+ RelocationPtr rv;
auto* ptr = new FFIPointer(info);
rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::FfiPointer) );
return rv;
}
-AllocationPtr::AllocationPtr(const AllocationPtr& x):
+RelocationPtr::RelocationPtr(const RelocationPtr& x):
m_ptr(nullptr)
{
if( x )
{
switch(x.get_ty())
{
- case Ty::Allocation:
- m_ptr = x.m_ptr;
- assert(alloc().refcount != 0);
- assert(alloc().refcount != SIZE_MAX);
- alloc().refcount += 1;
- //LOG_DEBUG(&alloc() << " REF++ " << alloc().refcount);
- break;
+ case Ty::Allocation: {
+ auto tmp = AllocationHandle( reinterpret_cast<Allocation*>(x.get_ptr()) );
+ *this = RelocationPtr::new_alloc(tmp);
+ tmp.m_ptr = nullptr;
+ } break;
case Ty::Function: {
auto ptr_i = reinterpret_cast<uintptr_t>(new ::HIR::Path(x.fcn()));
assert( (ptr_i & 3) == 0 );
@@ -75,21 +109,15 @@ AllocationPtr::AllocationPtr(const AllocationPtr& x):
m_ptr = nullptr;
}
}
-AllocationPtr::~AllocationPtr()
+RelocationPtr::~RelocationPtr()
{
if( *this )
{
switch(get_ty())
{
- case Ty::Allocation: {
- auto* ptr = &alloc();
- ptr->refcount -= 1;
- //LOG_DEBUG(&alloc() << " REF-- " << ptr->refcount);
- if(ptr->refcount == 0)
- {
- delete ptr;
- }
- } break;
+ case Ty::Allocation:
+ (void)AllocationHandle( reinterpret_cast<Allocation*>(get_ptr()) );
+ break;
case Ty::Function: {
auto* ptr = const_cast<::HIR::Path*>(&fcn());
delete ptr;
@@ -104,7 +132,7 @@ AllocationPtr::~AllocationPtr()
}
}
}
-size_t AllocationPtr::get_size() const
+size_t RelocationPtr::get_size() const
{
if( !*this )
return 0;
@@ -123,22 +151,22 @@ size_t AllocationPtr::get_size() const
throw "Unreachable";
}
-::std::ostream& operator<<(::std::ostream& os, const AllocationPtr& x)
+::std::ostream& operator<<(::std::ostream& os, const RelocationPtr& x)
{
if( x )
{
switch(x.get_ty())
{
- case AllocationPtr::Ty::Allocation:
+ case RelocationPtr::Ty::Allocation:
os << &x.alloc();
break;
- case AllocationPtr::Ty::Function:
+ case RelocationPtr::Ty::Function:
os << x.fcn();
break;
- case AllocationPtr::Ty::StdString:
+ case RelocationPtr::Ty::StdString:
os << "\"" << x.str() << "\"";
break;
- case AllocationPtr::Ty::FfiPointer:
+ case RelocationPtr::Ty::FfiPointer:
os << "FFI " << x.ffi().source_function << " " << x.ffi().ptr_value;
break;
}
@@ -150,9 +178,93 @@ size_t AllocationPtr::get_size() const
return os;
}
+uint64_t ValueCommonRead::read_usize(size_t ofs) const
+{
+ uint64_t v = 0;
+ this->read_bytes(ofs, &v, POINTER_SIZE);
+ return v;
+}
+void ValueCommonWrite::write_usize(size_t ofs, uint64_t v)
+{
+ this->write_bytes(ofs, &v, POINTER_SIZE);
+}
+void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_size, bool& out_is_mut) const
+{
+ auto ofs = read_usize(rd_ofs);
+ auto reloc = get_relocation(rd_ofs);
+ if( !reloc )
+ {
+ if( ofs != 0 ) {
+ LOG_FATAL("Read a non-zero offset with no relocation");
+ }
+ if( req_valid > 0 ) {
+ LOG_ERROR("Attempting to read a null pointer");
+ }
+ out_is_mut = false;
+ out_size = 0;
+ return nullptr;
+ }
+ else
+ {
+ switch(reloc.get_ty())
+ {
+ case RelocationPtr::Ty::Allocation: {
+ auto& a = reloc.alloc();
+ if( ofs > a.size() )
+ LOG_FATAL("Out-of-bounds pointer");
+ if( ofs + req_valid > a.size() )
+ LOG_FATAL("Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << a.size());
+ a.check_bytes_valid( ofs, req_valid );
+ out_size = a.size() - ofs;
+ out_is_mut = true;
+ return a.data_ptr() + ofs;
+ }
+ case RelocationPtr::Ty::StdString: {
+ const auto& s = reloc.str();
+ if( ofs > s.size() )
+ LOG_FATAL("Out-of-bounds pointer");
+ if( ofs + req_valid > s.size() )
+ LOG_FATAL("Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << s.size());
+ out_size = s.size() - ofs;
+ out_is_mut = false;
+ return const_cast<void*>( static_cast<const void*>(s.data() + ofs) );
+ }
+ case RelocationPtr::Ty::Function:
+ LOG_FATAL("read_pointer w/ function");
+ case RelocationPtr::Ty::FfiPointer: {
+ const auto& f = reloc.ffi();
+ // TODO: Validity?
+ //if( req_valid )
+ // LOG_FATAL("Can't request valid data from a FFI pointer");
+ // TODO: Have an idea of mutability and available size from FFI
+ out_size = f.size - ofs;
+ out_is_mut = false;
+ return reloc.ffi().ptr_value + ofs;
+ }
+ }
+ throw "";
+ }
+}
+ValueRef ValueCommonRead::read_pointer_valref_mut(size_t rd_ofs, size_t size)
+{
+ auto ofs = read_usize(rd_ofs);
+ auto reloc = get_relocation(rd_ofs);
+ if( !reloc )
+ {
+ LOG_ERROR("Getting ValRef to null pointer (no relocation)");
+ }
+ else
+ {
+ // TODO: Validate size
+ return ValueRef(reloc, ofs, size);
+ }
+}
+
void Allocation::resize(size_t new_size)
{
+ if( this->is_freed )
+ LOG_ERROR("Use of freed memory " << this);
//size_t old_size = this->size();
//size_t extra_bytes = (new_size > old_size ? new_size - old_size : 0);
@@ -167,9 +279,9 @@ void Allocation::check_bytes_valid(size_t ofs, size_t size) const
}
for(size_t i = ofs; i < ofs + size; i++)
{
- if( !(this->mask[i/8] & (1 << i%8)) )
+ if( !(this->mask[i/8] & (1 << (i%8))) )
{
- ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl;
+ LOG_ERROR("Invalid bytes in value - " << ofs << "+" << size << " - " << *this);
throw "ERROR";
}
}
@@ -179,14 +291,18 @@ void Allocation::mark_bytes_valid(size_t ofs, size_t size)
assert( ofs+size <= this->mask.size() * 8 );
for(size_t i = ofs; i < ofs + size; i++)
{
- this->mask[i/8] |= (1 << i%8);
+ this->mask[i/8] |= (1 << (i%8));
}
}
Value Allocation::read_value(size_t ofs, size_t size) const
{
Value rv;
+ TRACE_FUNCTION_R("Allocation::read_value " << this << " " << ofs << "+" << size, *this << " | " << rv);
+ if( this->is_freed )
+ LOG_ERROR("Use of freed memory " << this);
+ LOG_DEBUG(*this);
- // TODO: Determine if this can become an inline allocation.
+ // Determine if this can become an inline allocation.
bool has_reloc = false;
for(const auto& r : this->relocations)
{
@@ -205,7 +321,7 @@ Value Allocation::read_value(size_t ofs, size_t size) const
{
if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size )
{
- rv.allocation.alloc().relocations.push_back({ r.slot_ofs - ofs, r.backing_alloc });
+ rv.allocation->relocations.push_back({ r.slot_ofs - ofs, r.backing_alloc });
}
}
@@ -213,14 +329,12 @@ Value Allocation::read_value(size_t ofs, size_t size) const
for(size_t i = 0; i < size; i ++)
{
size_t j = ofs + i;
- bool v = (this->mask[j/8] & (1 << j%8)) != 0;
+ const uint8_t test_mask = (1 << (j%8));
+ const uint8_t set_mask = (1 << (i%8));
+ bool v = (this->mask[j/8] & test_mask) != 0;
if( v )
{
- rv.allocation.alloc().mask[i/8] |= (1 << i%8);
- }
- else
- {
- rv.allocation.alloc().mask[i/8] &= ~(1 << i%8);
+ rv.allocation->mask[i/8] |= set_mask;
}
}
}
@@ -236,21 +350,23 @@ Value Allocation::read_value(size_t ofs, size_t size) const
for(size_t i = 0; i < size; i ++)
{
size_t j = ofs + i;
- bool v = (this->mask[j/8] & (1 << j%8)) != 0;
+ const uint8_t tst_mask = 1 << (j%8);
+ const uint8_t set_mask = 1 << (i%8);
+ bool v = (this->mask[j/8] & tst_mask) != 0;
if( v )
{
- rv.direct_data.mask[i/8] |= (1 << i%8);
+ rv.direct_data.mask[i/8] |= set_mask;
}
- //else
- //{
- // rv.direct_data.mask[i/8] &= ~(1 << i%8);
- //}
}
}
return rv;
}
void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const
{
+ if( this->is_freed )
+ LOG_ERROR("Use of freed memory " << this);
+
+ LOG_DEBUG("Allocation::read_bytes " << this << " " << ofs << "+" << count);
if(count == 0)
return ;
@@ -273,10 +389,15 @@ void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const
}
void Allocation::write_value(size_t ofs, Value v)
{
+ TRACE_FUNCTION_R("Allocation::write_value " << this << " " << ofs << "+" << v.size() << " " << v, *this);
+ if( this->is_freed )
+ LOG_ERROR("Use of freed memory " << this);
+ //if( this->is_read_only )
+ // LOG_ERROR("Writing to read-only allocation " << this);
if( v.allocation )
{
- size_t v_size = v.allocation.alloc().size();
- const auto& src_alloc = v.allocation.alloc();
+ size_t v_size = v.allocation->size();
+ const auto& src_alloc = *v.allocation;
// Take a copy of the source mask
auto s_mask = src_alloc.mask;
@@ -337,8 +458,15 @@ void Allocation::write_value(size_t ofs, Value v)
}
void Allocation::write_bytes(size_t ofs, const void* src, size_t count)
{
+ //LOG_DEBUG("Allocation::write_bytes " << this << " " << ofs << "+" << count);
+ if( this->is_freed )
+ LOG_ERROR("Use of freed memory " << this);
+ //if( this->is_read_only )
+ // LOG_ERROR("Writing to read-only allocation " << this);
+
if(count == 0)
return ;
+ TRACE_FUNCTION_R("Allocation::write_bytes " << this << " " << ofs << "+" << count, *this);
if(ofs >= this->size() ) {
LOG_ERROR("Out of bounds write, " << ofs << "+" << count << " > " << this->size());
throw "ERROR";
@@ -371,9 +499,10 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count)
::std::memcpy(this->data_ptr() + ofs, src, count);
mark_bytes_valid(ofs, count);
}
-void Allocation::write_usize(size_t ofs, uint64_t v)
+void Allocation::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc)
{
- this->write_bytes(ofs, &v, POINTER_SIZE);
+ this->write_usize(ofs, ptr_ofs);
+ this->relocations.push_back(Relocation { ofs, /*POINTER_SIZE,*/ ::std::move(reloc) });
}
::std::ostream& operator<<(::std::ostream& os, const Allocation& x)
{
@@ -384,7 +513,7 @@ void Allocation::write_usize(size_t ofs, uint64_t v)
if( i != 0 )
os << " ";
- if( x.mask[i/8] & (1 << i%8) )
+ if( x.mask[i/8] & (1 << (i%8)) )
{
os << ::std::setw(2) << ::std::setfill('0') << (int)x.data_ptr()[i];
}
@@ -416,38 +545,12 @@ Value::Value()
Value::Value(::HIR::TypeRef ty)
{
size_t size = ty.get_size();
-#if 1
+
// Support inline data if the data will fit within the inline region (which is the size of the metadata)
if( ty.get_size() <= sizeof(this->direct_data.data) )
{
- struct H
- {
- static bool has_pointer(const ::HIR::TypeRef& ty)
- {
- if( ty.wrappers.empty() || ::std::all_of(ty.wrappers.begin(), ty.wrappers.end(), [](const auto& x){ return x.type == TypeWrapper::Ty::Array; }) )
- {
- // TODO: Function pointers should be _pointers_
- if( ty.inner_type == RawType::Function )
- {
- return true;
- }
- // Check the inner type
- if( ty.inner_type != RawType::Composite )
- {
- return false;
- }
- // Still not sure, check the inner for any pointers.
- for(const auto& fld : ty.composite_type->fields)
- {
- if( H::has_pointer(fld.second) )
- return true;
- }
- return false;
- }
- return true;
- }
- };
- if( ! H::has_pointer(ty) )
+ // AND the type doesn't contain a pointer (of any kind)
+ if( ! ty.has_pointer() )
{
// Will fit in a inline allocation, nice.
//LOG_TRACE("No pointers in " << ty << ", storing inline");
@@ -457,7 +560,6 @@ Value::Value(::HIR::TypeRef ty)
return ;
}
}
-#endif
// Fallback: Make a new allocation
//LOG_TRACE(" Creating allocation for " << ty);
@@ -482,18 +584,46 @@ Value Value::new_fnptr(const ::HIR::Path& fn_path)
{
Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::Function }) );
assert(rv.allocation);
- rv.allocation.alloc().relocations.push_back(Relocation { 0, AllocationPtr::new_fcn(fn_path) });
- rv.allocation.alloc().data.at(0) = 0;
- rv.allocation.alloc().mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes
+ rv.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_fcn(fn_path) });
+ rv.allocation->data.at(0) = 0;
+ rv.allocation->mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes
return rv;
}
Value Value::new_ffiptr(FFIPointer ffi)
{
Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::USize }) );
rv.create_allocation();
- rv.allocation.alloc().relocations.push_back(Relocation { 0, AllocationPtr::new_ffi(ffi) });
- rv.allocation.alloc().data.at(0) = 0;
- rv.allocation.alloc().mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes
+ rv.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_ffi(ffi) });
+ rv.allocation->data.at(0) = 0;
+ rv.allocation->mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes
+ return rv;
+}
+Value Value::new_pointer(::HIR::TypeRef ty, uint64_t v, RelocationPtr r) {
+ assert(ty.get_wrapper());
+ assert(ty.get_wrapper()->type == TypeWrapper::Ty::Borrow || ty.get_wrapper()->type == TypeWrapper::Ty::Pointer);
+ Value rv(ty);
+ rv.write_usize(0, v);
+ rv.allocation->relocations.push_back(Relocation { 0, /*POINTER_SIZE,*/ ::std::move(r) });
+ return rv;
+}
+Value Value::new_usize(uint64_t v) {
+ Value rv( ::HIR::TypeRef(RawType::USize) );
+ rv.write_usize(0, v);
+ return rv;
+}
+Value Value::new_isize(int64_t v) {
+ Value rv( ::HIR::TypeRef(RawType::ISize) );
+ rv.write_isize(0, v);
+ return rv;
+}
+Value Value::new_u32(uint32_t v) {
+ Value rv( ::HIR::TypeRef(RawType::U32) );
+ rv.write_u32(0, v);
+ return rv;
+}
+Value Value::new_i32(int32_t v) {
+ Value rv( ::HIR::TypeRef(RawType::I32) );
+ rv.write_i32(0, v);
return rv;
}
@@ -502,10 +632,10 @@ void Value::create_allocation()
assert(!this->allocation);
this->allocation = Allocation::new_alloc(this->direct_data.size);
if( this->direct_data.size > 0 )
- this->allocation.alloc().mask[0] = this->direct_data.mask[0];
+ this->allocation->mask[0] = this->direct_data.mask[0];
if( this->direct_data.size > 8 )
- this->allocation.alloc().mask[1] = this->direct_data.mask[1];
- ::std::memcpy(this->allocation.alloc().data.data(), this->direct_data.data, this->direct_data.size);
+ this->allocation->mask[1] = this->direct_data.mask[1];
+ ::std::memcpy(this->allocation->data.data(), this->direct_data.data, this->direct_data.size);
}
void Value::check_bytes_valid(size_t ofs, size_t size) const
{
@@ -513,7 +643,7 @@ void Value::check_bytes_valid(size_t ofs, size_t size) const
return ;
if( this->allocation )
{
- this->allocation.alloc().check_bytes_valid(ofs, size);
+ this->allocation->check_bytes_valid(ofs, size);
}
else
{
@@ -542,7 +672,7 @@ void Value::mark_bytes_valid(size_t ofs, size_t size)
{
if( this->allocation )
{
- this->allocation.alloc().mark_bytes_valid(ofs, size);
+ this->allocation->mark_bytes_valid(ofs, size);
}
else
{
@@ -559,7 +689,7 @@ Value Value::read_value(size_t ofs, size_t size) const
//TRACE_FUNCTION_R(ofs << ", " << size << ") - " << *this, rv);
if( this->allocation )
{
- rv = this->allocation.alloc().read_value(ofs, size);
+ rv = this->allocation->read_value(ofs, size);
}
else
{
@@ -577,7 +707,7 @@ void Value::read_bytes(size_t ofs, void* dst, size_t count) const
return ;
if( this->allocation )
{
- this->allocation.alloc().read_bytes(ofs, dst, count);
+ this->allocation->read_bytes(ofs, dst, count);
}
else
{
@@ -605,7 +735,7 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count)
return ;
if( this->allocation )
{
- this->allocation.alloc().write_bytes(ofs, src, count);
+ this->allocation->write_bytes(ofs, src, count);
}
else
{
@@ -626,14 +756,14 @@ void Value::write_value(size_t ofs, Value v)
{
if( this->allocation )
{
- this->allocation.alloc().write_value(ofs, ::std::move(v));
+ this->allocation->write_value(ofs, ::std::move(v));
}
else
{
- if( v.allocation && !v.allocation.alloc().relocations.empty() )
+ if( v.allocation && !v.allocation->relocations.empty() )
{
this->create_allocation();
- this->allocation.alloc().write_value(ofs, ::std::move(v));
+ this->allocation->write_value(ofs, ::std::move(v));
}
else
{
@@ -651,16 +781,20 @@ void Value::write_value(size_t ofs, Value v)
}
}
}
-void Value::write_usize(size_t ofs, uint64_t v)
+void Value::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc)
{
- this->write_bytes(ofs, &v, POINTER_SIZE);
+ if( !this->allocation )
+ {
+ LOG_ERROR("Writing a pointer with no allocation");
+ }
+ this->allocation->write_ptr(ofs, ptr_ofs, ::std::move(reloc));
}
::std::ostream& operator<<(::std::ostream& os, const Value& v)
{
if( v.allocation )
{
- os << v.allocation.alloc();
+ os << *v.allocation;
}
else
{
@@ -687,15 +821,15 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
{
if( v.m_size == 0 )
return os;
- if( v.m_alloc || v.m_value->allocation )
+ if( v.m_alloc )
{
- const auto& alloc_ptr = v.m_alloc ? v.m_alloc : v.m_value->allocation;
+ const auto& alloc_ptr = v.m_alloc;;
// TODO: What if alloc_ptr isn't a data allocation?
switch(alloc_ptr.get_ty())
{
- case AllocationPtr::Ty::Allocation: {
+ case RelocationPtr::Ty::Allocation: {
const auto& alloc = alloc_ptr.alloc();
-
+
auto flags = os.flags();
os << ::std::hex;
for(size_t i = v.m_offset; i < ::std::min(alloc.size(), v.m_offset + v.m_size); i++)
@@ -724,10 +858,10 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
}
os << " }";
} break;
- case AllocationPtr::Ty::Function:
+ case RelocationPtr::Ty::Function:
LOG_TODO("ValueRef to " << alloc_ptr);
break;
- case AllocationPtr::Ty::StdString: {
+ case RelocationPtr::Ty::StdString: {
const auto& s = alloc_ptr.str();
assert(v.m_offset < s.size());
assert(v.m_size < s.size());
@@ -740,12 +874,44 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
}
os.setf(flags);
} break;
- case AllocationPtr::Ty::FfiPointer:
+ case RelocationPtr::Ty::FfiPointer:
LOG_TODO("ValueRef to " << alloc_ptr);
break;
}
}
- else
+ else if( v.m_value && v.m_value->allocation )
+ {
+ const auto& alloc = *v.m_value->allocation;
+
+ auto flags = os.flags();
+ os << ::std::hex;
+ for(size_t i = v.m_offset; i < ::std::min(alloc.size(), v.m_offset + v.m_size); i++)
+ {
+ if( i != 0 )
+ os << " ";
+
+ if( alloc.mask[i/8] & (1 << i%8) )
+ {
+ os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[i];
+ }
+ else
+ {
+ os << "--";
+ }
+ }
+ os.setf(flags);
+
+ os << " {";
+ for(const auto& r : alloc.relocations)
+ {
+ if( v.m_offset <= r.slot_ofs && r.slot_ofs < v.m_offset + v.m_size )
+ {
+ os << " @" << (r.slot_ofs - v.m_offset) << "=" << r.backing_alloc;
+ }
+ }
+ os << " }";
+ }
+ else if( v.m_value )
{
const auto& direct = v.m_value->direct_data;
@@ -766,24 +932,45 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
}
os.setf(flags);
}
+ else
+ {
+ // TODO: no value?
+ }
return os;
}
-uint64_t ValueRef::read_usize(size_t ofs) const
+Value ValueRef::read_value(size_t ofs, size_t size) const
{
- uint64_t v = 0;
- this->read_bytes(ofs, &v, POINTER_SIZE);
- return v;
+ if( size == 0 )
+ return Value();
+ if( !(ofs < m_size && size <= m_size && ofs + size <= m_size) ) {
+ LOG_ERROR("Read exceeds bounds, " << ofs << " + " << size << " > " << m_size << " - from " << *this);
+ }
+ if( m_alloc ) {
+ switch(m_alloc.get_ty())
+ {
+ case RelocationPtr::Ty::Allocation:
+ return m_alloc.alloc().read_value(m_offset + ofs, size);
+ case RelocationPtr::Ty::StdString: {
+ auto rv = Value::with_size(size, false);
+ //ASSERT_BUG(ofs <= m_alloc.str().size(), "");
+ //ASSERT_BUG(size <= m_alloc.str().size(), "");
+ //ASSERT_BUG(ofs+size <= m_alloc.str().size(), "");
+ assert(m_offset+ofs <= m_alloc.str().size() && size <= m_alloc.str().size() && m_offset+ofs+size <= m_alloc.str().size());
+ rv.write_bytes(0, m_alloc.str().data() + m_offset + ofs, size);
+ return rv;
+ }
+ default:
+ //ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << );
+ throw "TODO";
+ }
+ }
+ else {
+ return m_value->read_value(m_offset + ofs, size);
+ }
}
-uint64_t Value::read_usize(size_t ofs) const
+bool ValueRef::compare(const void* other, size_t other_len) const
{
- uint64_t v = 0;
- this->read_bytes(ofs, &v, POINTER_SIZE);
- return v;
+ check_bytes_valid(0, other_len);
+ return ::std::memcmp(data_ptr(), other, other_len) == 0;
}
-uint64_t Allocation::read_usize(size_t ofs) const
-{
- uint64_t v = 0;
- this->read_bytes(ofs, &v, POINTER_SIZE);
- return v;
-} \ No newline at end of file
diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp
index 8b103210..b057b3c4 100644
--- a/tools/standalone_miri/value.hpp
+++ b/tools/standalone_miri/value.hpp
@@ -1,11 +1,16 @@
-//
-//
-//
+/*
+ * mrustc Standalone MIRI
+ * - by John Hodge (Mutabah)
+ *
+ * value.hpp
+ * - Runtime values
+ */
#pragma once
#include <vector>
#include <memory>
#include <cstdint>
+#include <cstring> // memcpy
#include <cassert>
namespace HIR {
@@ -14,19 +19,55 @@ namespace HIR {
}
class Allocation;
struct Value;
+struct ValueRef;
struct FFIPointer
{
const char* source_function;
void* ptr_value;
+ size_t size;
};
-class AllocationPtr
+class AllocationHandle
{
friend class Allocation;
- void* m_ptr;
+ friend class RelocationPtr;
+ Allocation* m_ptr;
+
+private:
+ AllocationHandle(Allocation* p):
+ m_ptr(p)
+ {
+ }
public:
+ AllocationHandle(): m_ptr(nullptr) {}
+ AllocationHandle(AllocationHandle&& x): m_ptr(x.m_ptr) {
+ x.m_ptr = nullptr;
+ }
+ AllocationHandle(const AllocationHandle& x);
+ ~AllocationHandle();
+ AllocationHandle& operator=(const AllocationHandle& x) = delete;
+ AllocationHandle& operator=(AllocationHandle&& x) {
+ this->~AllocationHandle();
+ this->m_ptr = x.m_ptr;
+ x.m_ptr = nullptr;
+ return *this;
+ }
+
+ operator bool() const { return m_ptr != 0; }
+ const Allocation& operator*() const { assert(m_ptr); return *m_ptr; }
+ Allocation& operator*() { assert(m_ptr); return *m_ptr; }
+ const Allocation* operator->() const { assert(m_ptr); return m_ptr; }
+ Allocation* operator->() { assert(m_ptr); return m_ptr; }
+};
+
+// TODO: Split into RelocationPtr and AllocationHandle
+class RelocationPtr
+{
+ void* m_ptr;
+
+public:
enum class Ty
{
Allocation,
@@ -35,26 +76,20 @@ public:
FfiPointer,
};
-private:
- AllocationPtr(Allocation* p):
- m_ptr(p)
- {
- }
-public:
- AllocationPtr(): m_ptr(nullptr) {}
- AllocationPtr(AllocationPtr&& x): m_ptr(x.m_ptr) {
+ RelocationPtr(): m_ptr(nullptr) {}
+ RelocationPtr(RelocationPtr&& x): m_ptr(x.m_ptr) {
x.m_ptr = nullptr;
}
- AllocationPtr(const AllocationPtr& x);
- ~AllocationPtr();
- static AllocationPtr new_fcn(::HIR::Path p);
- //static AllocationPtr new_rawdata(const void* buf, size_t len);
- static AllocationPtr new_string(const ::std::string* s); // NOTE: The string must have a stable pointer
- static AllocationPtr new_ffi(FFIPointer info);
-
- AllocationPtr& operator=(const AllocationPtr& x) = delete;
- AllocationPtr& operator=(AllocationPtr&& x) {
- this->~AllocationPtr();
+ RelocationPtr(const RelocationPtr& x);
+ ~RelocationPtr();
+ static RelocationPtr new_alloc(AllocationHandle h);
+ static RelocationPtr new_fcn(::HIR::Path p);
+ static RelocationPtr new_string(const ::std::string* s); // NOTE: The string must have a stable pointer
+ static RelocationPtr new_ffi(FFIPointer info);
+
+ RelocationPtr& operator=(const RelocationPtr& x) = delete;
+ RelocationPtr& operator=(RelocationPtr&& x) {
+ this->~RelocationPtr();
this->m_ptr = x.m_ptr;
x.m_ptr = nullptr;
return *this;
@@ -96,7 +131,7 @@ public:
return static_cast<Ty>( reinterpret_cast<uintptr_t>(m_ptr) & 3 );
}
- friend ::std::ostream& operator<<(::std::ostream& os, const AllocationPtr& x);
+ friend ::std::ostream& operator<<(::std::ostream& os, const RelocationPtr& x);
private:
void* get_ptr() const {
return reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(m_ptr) & ~3 );
@@ -107,15 +142,77 @@ struct Relocation
// Offset within parent allocation where this relocation is performed.
// TODO: Size?
size_t slot_ofs;
- AllocationPtr backing_alloc;
+ RelocationPtr backing_alloc;
+};
+
+// TODO: Split write and read
+struct ValueCommonRead
+{
+ virtual RelocationPtr get_relocation(size_t ofs) const = 0;
+ virtual void read_bytes(size_t ofs, void* dst, size_t count) const = 0;
+
+ uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; }
+ uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; }
+ uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; }
+ uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; }
+ int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); }
+ int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); }
+ int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); }
+ int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); }
+ float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; }
+ double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; }
+ uint64_t read_usize(size_t ofs) const;
+ int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); }
+
+ /// Read a pointer from the value, requiring at least `req_valid` valid bytes, saves avaliable space in `size`
+ void* read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& size, bool& is_mut) const;
+ /// Read a pointer, requiring `req_len` valid bytes
+ const void* read_pointer_const(size_t rd_ofs, size_t req_len) const {
+ size_t tmp;
+ bool is_mut;
+ return read_pointer_unsafe(rd_ofs, req_len, tmp, is_mut);
+ }
+ /// Read a pointer, not requiring that the target be initialised
+ void* read_pointer_uninit(size_t rd_ofs, size_t& out_size) {
+ bool is_mut;
+ void* rv = read_pointer_unsafe(rd_ofs, 0, out_size, is_mut);
+ if(!is_mut)
+ throw "";
+ //LOG_FATAL("Attempting to get an uninit pointer to immutable data");
+ return rv;
+ }
+ /// Read a pointer and return a ValueRef to it (mutable data)
+ ValueRef read_pointer_valref_mut(size_t rd_ofs, size_t size);
};
-class Allocation
+struct ValueCommonWrite:
+ public ValueCommonRead
{
- friend class AllocationPtr;
+ virtual void write_bytes(size_t ofs, const void* src, size_t count) = 0;
+
+ void write_u8 (size_t ofs, uint8_t v) { write_bytes(ofs, &v, 1); }
+ void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); }
+ void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); }
+ void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); }
+ void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); }
+ void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); }
+ void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); }
+ void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); }
+ void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); }
+ void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); }
+ void write_usize(size_t ofs, uint64_t v);
+ void write_isize(size_t ofs, int64_t v) { write_usize(ofs, static_cast<uint64_t>(v)); }
+ virtual void write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) = 0;
+};
+
+class Allocation:
+ public ValueCommonWrite
+{
+ friend class AllocationHandle;
size_t refcount;
// TODO: Read-only flag?
+ bool is_freed = false;
public:
- static AllocationPtr new_alloc(size_t size);
+ static AllocationHandle new_alloc(size_t size);
const uint8_t* data_ptr() const { return reinterpret_cast<const uint8_t*>(this->data.data()); }
uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->data.data()); }
@@ -125,17 +222,19 @@ public:
::std::vector<uint8_t> mask;
::std::vector<Relocation> relocations;
- AllocationPtr get_relocation(size_t ofs) const {
+ RelocationPtr get_relocation(size_t ofs) const override {
for(const auto& r : relocations) {
if(r.slot_ofs == ofs)
return r.backing_alloc;
}
- return AllocationPtr();
+ return RelocationPtr();
+ }
+ void mark_as_freed() {
+ is_freed = true;
+ relocations.clear();
+ for(auto& v : mask)
+ v = 0;
}
- //void mark_as_freed() {
- // for(auto& v : mask)
- // v = 0;
- //}
void resize(size_t new_size);
@@ -143,127 +242,102 @@ public:
void mark_bytes_valid(size_t ofs, size_t size);
Value read_value(size_t ofs, size_t size) const;
- void read_bytes(size_t ofs, void* dst, size_t count) const;
+ void read_bytes(size_t ofs, void* dst, size_t count) const override;
void write_value(size_t ofs, Value v);
- void write_bytes(size_t ofs, const void* src, size_t count);
-
- // TODO: Make this block common
- void write_u8 (size_t ofs, uint8_t v) { write_bytes(ofs, &v, 1); }
- void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); }
- void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); }
- void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); }
- void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); }
- void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); }
- void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); }
- void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); }
- void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); }
- void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); }
- void write_usize(size_t ofs, uint64_t v);
- void write_isize(size_t ofs, int64_t v) { write_usize(ofs, static_cast<uint64_t>(v)); }
-
- uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; }
- uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; }
- uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; }
- uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; }
- int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); }
- int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); }
- int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); }
- int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); }
- float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; }
- double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; }
- uint64_t read_usize(size_t ofs) const;
- int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); }
+ void write_bytes(size_t ofs, const void* src, size_t count) override;
+ void write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) override;
};
extern ::std::ostream& operator<<(::std::ostream& os, const Allocation& x);
-struct Value
+struct Value:
+ public ValueCommonWrite
{
// If NULL, data is direct
- AllocationPtr allocation;
+ AllocationHandle allocation;
struct {
- uint8_t data[2*sizeof(size_t)-3]; // 16-3 = 13, fits in 16 bits of mask
+ // NOTE: Can't pack the mask+size tighter, need 4 bits of size (8-15) leaving 12 bits of mask
+ uint8_t data[2*8-3]; // 13 data bytes, plus 16bit mask, plus size = 16 bytes
uint8_t mask[2];
uint8_t size;
} direct_data;
Value();
Value(::HIR::TypeRef ty);
+
static Value with_size(size_t size, bool have_allocation);
static Value new_fnptr(const ::HIR::Path& fn_path);
static Value new_ffiptr(FFIPointer ffi);
+ static Value new_pointer(::HIR::TypeRef ty, uint64_t v, RelocationPtr r);
+ static Value new_usize(uint64_t v);
+ static Value new_isize(int64_t v);
+ static Value new_u32(uint32_t v);
+ static Value new_i32(int32_t v);
void create_allocation();
- size_t size() const { return allocation ? allocation.alloc().size() : direct_data.size; }
+ size_t size() const { return allocation ? allocation->size() : direct_data.size; }
+ const uint8_t* data_ptr() const { return allocation ? allocation->data_ptr() : direct_data.data; }
+ uint8_t* data_ptr() { return allocation ? allocation->data_ptr() : direct_data.data; }
+
+ RelocationPtr get_relocation(size_t ofs) const override {
+ if( this->allocation && this->allocation )
+ return this->allocation->get_relocation(ofs);
+ else
+ return RelocationPtr();
+ }
void check_bytes_valid(size_t ofs, size_t size) const;
void mark_bytes_valid(size_t ofs, size_t size);
Value read_value(size_t ofs, size_t size) const;
- void read_bytes(size_t ofs, void* dst, size_t count) const;
+ void read_bytes(size_t ofs, void* dst, size_t count) const override;
void write_value(size_t ofs, Value v);
- void write_bytes(size_t ofs, const void* src, size_t count);
+ void write_bytes(size_t ofs, const void* src, size_t count) override;
- // TODO: Make this block common
- void write_u8 (size_t ofs, uint8_t v) { write_bytes(ofs, &v, 1); }
- void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); }
- void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); }
- void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); }
- void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); }
- void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); }
- void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); }
- void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); }
- void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); }
- void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); }
- void write_usize(size_t ofs, uint64_t v);
- void write_isize(size_t ofs, int64_t v) { write_usize(ofs, static_cast<uint64_t>(v)); }
-
- uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; }
- uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; }
- uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; }
- uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; }
- int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); }
- int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); }
- int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); }
- int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); }
- float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; }
- double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; }
- uint64_t read_usize(size_t ofs) const;
- int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); }
+ void write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) override;
};
extern ::std::ostream& operator<<(::std::ostream& os, const Value& v);
// A read-only reference to a value (to write, you have to go through it)
-struct ValueRef
+struct ValueRef:
+ public ValueCommonRead
{
- // Either an AllocationPtr, or a Value pointer
- AllocationPtr m_alloc;
+ // Either an AllocationHandle, or a Value pointer
+ RelocationPtr m_alloc;
Value* m_value;
size_t m_offset; // Offset within the value
size_t m_size; // Size in bytes of the referenced value
::std::shared_ptr<Value> m_metadata;
- ValueRef(AllocationPtr ptr, size_t ofs, size_t size):
+ ValueRef(RelocationPtr ptr, size_t ofs, size_t size):
m_alloc(ptr),
m_value(nullptr),
m_offset(ofs),
m_size(size)
{
- switch(m_alloc.get_ty())
+ if( m_alloc )
{
- case AllocationPtr::Ty::Allocation:
- assert(ofs < m_alloc.alloc().size());
- assert(size <= m_alloc.alloc().size());
- assert(ofs+size <= m_alloc.alloc().size());
- break;
- case AllocationPtr::Ty::StdString:
- assert(ofs < m_alloc.str().size());
- assert(size <= m_alloc.str().size());
- assert(ofs+size <= m_alloc.str().size());
- break;
- default:
- throw "TODO";
+ switch(m_alloc.get_ty())
+ {
+ case RelocationPtr::Ty::Allocation:
+ assert(ofs < m_alloc.alloc().size());
+ assert(size <= m_alloc.alloc().size());
+ assert(ofs+size <= m_alloc.alloc().size());
+ break;
+ case RelocationPtr::Ty::StdString:
+ assert(ofs < m_alloc.str().size());
+ assert(size <= m_alloc.str().size());
+ assert(ofs+size <= m_alloc.str().size());
+ break;
+ case RelocationPtr::Ty::FfiPointer:
+ assert(ofs < m_alloc.ffi().size);
+ assert(size <= m_alloc.ffi().size);
+ assert(ofs+size <= m_alloc.ffi().size);
+ break;
+ default:
+ throw "TODO";
+ }
}
}
ValueRef(Value& val):
@@ -277,56 +351,70 @@ struct ValueRef
{
}
- AllocationPtr get_relocation(size_t ofs) const {
+ RelocationPtr get_relocation(size_t ofs) const override {
if(m_alloc)
{
if( m_alloc.is_alloc() )
return m_alloc.alloc().get_relocation(ofs);
else
- return AllocationPtr();
+ return RelocationPtr();
}
- else if( m_value->allocation )
+ else if( m_value )
{
- if( m_value->allocation.is_alloc() )
- return m_value->allocation.alloc().get_relocation(ofs);
- else
- return AllocationPtr();
+ return m_value->get_relocation(ofs);
}
else
{
- return AllocationPtr();
+ return RelocationPtr();
+ }
+ }
+ Value read_value(size_t ofs, size_t size) const;
+ const uint8_t* data_ptr() const {
+ if( m_alloc ) {
+ switch(m_alloc.get_ty())
+ {
+ case RelocationPtr::Ty::Allocation:
+ return m_alloc.alloc().data_ptr() + m_offset;
+ break;
+ case RelocationPtr::Ty::StdString:
+ return reinterpret_cast<const uint8_t*>(m_alloc.str().data() + m_offset);
+ default:
+ throw "TODO";
+ }
+ }
+ else if( m_value ) {
+ return m_value->data_ptr() + m_offset;
+ }
+ else {
+ return nullptr;
}
}
- Value read_value(size_t ofs, size_t size) const {
+ void read_bytes(size_t ofs, void* dst, size_t size) const {
if( size == 0 )
- return Value();
+ return ;
assert(ofs < m_size);
assert(size <= m_size);
assert(ofs+size <= m_size);
if( m_alloc ) {
switch(m_alloc.get_ty())
{
- case AllocationPtr::Ty::Allocation:
- return m_alloc.alloc().read_value(m_offset + ofs, size);
- case AllocationPtr::Ty::StdString: {
- auto rv = Value::with_size(size, false);
- //ASSERT_BUG(ofs <= m_alloc.str().size(), "");
- //ASSERT_BUG(size <= m_alloc.str().size(), "");
- //ASSERT_BUG(ofs+size <= m_alloc.str().size(), "");
+ case RelocationPtr::Ty::Allocation:
+ m_alloc.alloc().read_bytes(m_offset + ofs, dst, size);
+ break;
+ case RelocationPtr::Ty::StdString:
assert(m_offset+ofs <= m_alloc.str().size() && size <= m_alloc.str().size() && m_offset+ofs+size <= m_alloc.str().size());
- rv.write_bytes(0, m_alloc.str().data() + m_offset + ofs, size);
- return rv;
- }
+ ::std::memcpy(dst, m_alloc.str().data() + m_offset + ofs, size);
+ break;
default:
//ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << );
throw "TODO";
}
}
else {
- return m_value->read_value(m_offset + ofs, size);
+ m_value->read_bytes(m_offset + ofs, dst, size);
}
}
- void read_bytes(size_t ofs, void* dst, size_t size) const {
+ void check_bytes_valid(size_t ofs, size_t size) const {
if( size == 0 )
return ;
assert(ofs < m_size);
@@ -335,12 +423,11 @@ struct ValueRef
if( m_alloc ) {
switch(m_alloc.get_ty())
{
- case AllocationPtr::Ty::Allocation:
- m_alloc.alloc().read_bytes(m_offset + ofs, dst, size);
+ case RelocationPtr::Ty::Allocation:
+ m_alloc.alloc().check_bytes_valid(m_offset + ofs, size);
break;
- case AllocationPtr::Ty::StdString:
+ case RelocationPtr::Ty::StdString:
assert(m_offset+ofs <= m_alloc.str().size() && size <= m_alloc.str().size() && m_offset+ofs+size <= m_alloc.str().size());
- ::std::memcpy(dst, m_alloc.str().data() + m_offset + ofs, size);
break;
default:
//ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << );
@@ -348,20 +435,10 @@ struct ValueRef
}
}
else {
- m_value->read_bytes(m_offset + ofs, dst, size);
+ m_value->check_bytes_valid(m_offset + ofs, size);
}
}
- uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; }
- uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; }
- uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; }
- uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; }
- int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); }
- int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); }
- int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); }
- int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); }
- float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; }
- double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; }
- uint64_t read_usize(size_t ofs) const;
- int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); }
+
+ bool compare(const void* other, size_t other_len) const;
};
extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v);
diff --git a/tools/testrunner/main.cpp b/tools/testrunner/main.cpp
index 63391fc5..f21dc7fa 100644
--- a/tools/testrunner/main.cpp
+++ b/tools/testrunner/main.cpp
@@ -93,6 +93,11 @@ bool run_compiler(const ::helpers::path& source_file, const ::helpers::path& out
{
::std::vector<const char*> args;
args.push_back("mrustc");
+
+ // Force optimised and debuggable
+ args.push_back("-O");
+ args.push_back("-g");
+
args.push_back("-L");
args.push_back("output");
if(libdir.is_valid())
@@ -336,6 +341,12 @@ int main(int argc, const char* argv[])
continue;
}
+ // If there's no pre-build files (dependencies), clear the dependency path (cleaner output)
+ if( test.m_pre_build.empty() )
+ {
+ depdir = ::helpers::path();
+ }
+
auto compile_logfile = outdir / test.m_name + "-build.log";
if( !run_compiler(test.m_path, outfile, test.m_extra_flags, depdir) )
{
@@ -355,12 +366,27 @@ int main(int argc, const char* argv[])
if( !run_executable(outfile, { outfile.str().c_str() }, run_out_file) )
{
DEBUG("RUN FAIL " << test.m_name);
+
+ // Move the failing output file
+ auto fail_file = run_out_file + "_failed";
+ remove(fail_file.str().c_str());
+ rename(run_out_file.str().c_str(), fail_file.str().c_str());
+ DEBUG("- Output in " << fail_file);
+
n_fail ++;
if( opts.fail_fast )
return 1;
else
continue;
}
+
+#ifdef __linux__
+ // Run `strip` on the test (if on linux)
+ // XXX: Make this cleaner, or remove the need for it (by dynamic linking libstd)
+ if( !run_executable("/usr/bin/strip", { "strip", outfile.str().c_str() }, "/dev/null") )
+ {
+ }
+#endif
}
else
{
@@ -528,10 +554,11 @@ bool run_executable(const ::helpers::path& exe_name, const ::std::vector<const c
auto argv = args;
argv.push_back(nullptr);
pid_t pid;
+ extern char** environ;
int rv = posix_spawn(&pid, exe_name.str().c_str(), &file_actions, nullptr, const_cast<char**>(argv.data()), environ);
if( rv != 0 )
{
- DEBUG("Error in posix_spawn - " << rv);
+ DEBUG("Error in posix_spawn of " << exe_name << " - " << rv);
return false;
}