From c1b43f71776fda5454bd84c2cc735a0509d44436 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 25 Apr 2018 12:33:19 +0800 Subject: HIR Dump - (minor), fix formatting of enums --- src/hir/dump.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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"; -- cgit v1.2.3 From 3b8d8f1a392a2cb5cad1d57d08ced693a0d197d8 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 25 Apr 2018 12:33:31 +0800 Subject: minicargo - Re-run build script if output is missing --- tools/minicargo/build.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index c7c07256..392e6a64 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -803,7 +803,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 +813,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(); -- cgit v1.2.3 From 144bd3cdcea986f907468074365dfd17893a0f0f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 12:52:46 +0800 Subject: Standalone Miri - Linux build support --- tools/standalone_miri/Makefile | 43 ++++++++++++++++++++++++++++++ tools/standalone_miri/debug.hpp | 4 +-- tools/standalone_miri/lex.cpp | 4 +++ tools/standalone_miri/main.cpp | 49 ++++++++++++++++++++++++++++++++++- tools/standalone_miri/mir.cpp | 1 + tools/standalone_miri/module_tree.cpp | 3 ++- tools/standalone_miri/value.hpp | 1 + 7 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 tools/standalone_miri/Makefile diff --git a/tools/standalone_miri/Makefile b/tools/standalone_miri/Makefile new file mode 100644 index 00000000..94c89452 --- /dev/null +++ b/tools/standalone_miri/Makefile @@ -0,0 +1,43 @@ +# +# 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 + +LINKFLAGS := -g -lpthread +CXXFLAGS := -Wall -std=c++14 -g -O2 +CXXFLAGS += -I ../common -I ../../src/include -I . + +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.hpp b/tools/standalone_miri/debug.hpp index 5afad96e..f7d32fe5 100644 --- a/tools/standalone_miri/debug.hpp +++ b/tools/standalone_miri/debug.hpp @@ -75,14 +75,14 @@ FunctionTrace 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"; } }; diff --git a/tools/standalone_miri/lex.cpp b/tools/standalone_miri/lex.cpp index 48a9e0cd..7cfe1a78 100644 --- a/tools/standalone_miri/lex.cpp +++ b/tools/standalone_miri/lex.cpp @@ -390,6 +390,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/main.cpp b/tools/standalone_miri/main.cpp index a75e753f..384bc79e 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -353,6 +353,21 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar ret.write_i32(0, 120); // ERROR_CALL_NOT_IMPLEMENTED return ret; } + + // - 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 ret; + } + + // - No stack overflow handling needed + if( path == ::HIR::SimplePath { "std", { "sys", "imp", "stack_overflow", "imp", "init" } } ) + { + return ret; + } } if( fcn.external.link_name != "" ) @@ -1162,6 +1177,9 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar case RawType::USize: new_val.write_usize( 0, Ops::do_bitwise(v_l.read_usize(0), v_r.read_usize(0), re.op) ); break; + case RawType::I32: + new_val.write_i32( 0, static_cast(Ops::do_bitwise(v_l.read_i32(0), v_r.read_i32(0), re.op)) ); + break; default: LOG_TODO("BinOp bitwise - " << se.src << " w/ " << ty_l); } @@ -1497,7 +1515,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar 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); + const 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(); @@ -1516,6 +1534,11 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar throw ""; } + +extern "C" { + long sysconf(int); +} + Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& abi, ::std::vector args) { if( link_name == "__rust_allocate" ) @@ -1631,6 +1654,25 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab return rv; } } +#else + // std C + else if( link_name == "signal" ) + { + LOG_DEBUG("Call `signal` - Ignoring and returning SIG_IGN"); + auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv.write_usize(0, 1); + return rv; + } + // POSIX + else if( link_name == "sysconf" ) + { + auto name = args.at(0).read_i32(0); + LOG_DEBUG("FFI sysconf(" << name << ")"); + long val = sysconf(name); + auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv.write_usize(0, val); + return rv; + } #endif // Allocators! else @@ -1728,6 +1770,11 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, const ::std::string& name, cons { 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" ) { 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 namespace std { template diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 2513140a..d62695d1 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 +#include // std::find #include "debug.hpp" ModuleTree::ModuleTree() @@ -1328,4 +1329,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/value.hpp b/tools/standalone_miri/value.hpp index 8b103210..fb5cc5ae 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -6,6 +6,7 @@ #include #include #include +#include // memcpy #include namespace HIR { -- cgit v1.2.3 From 2165fa41d051a4ce3fc1cddfe68a25fa65445706 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 12:56:06 +0800 Subject: minicargo.mk - Support building MMIR (and script to do so) --- minicargo.mk | 43 +++++++++++++++++++++++++++++-------------- test_smiri.sh | 6 ++++++ 2 files changed, 35 insertions(+), 14 deletions(-) create mode 100755 test_smiri.sh diff --git a/minicargo.mk b/minicargo.mk index c82474f9..0d2d4fb1 100644 --- a/minicargo.mk +++ b/minicargo.mk @@ -1,9 +1,24 @@ +# +# +# +OUTDIR_SUF ?= +MMIR ?= RUSTC_CHANNEL ?= stable RUSTC_VERSION ?= 1.19.0 OVERRIDE_SUFFIX ?= -linux -OUTDIR := output/ 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 @@ -40,20 +55,20 @@ $(MINICARGO): # - 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) + $(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) + $(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) + $(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) + $(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) + $(MINICARGO) lib/libproc_macro --output-dir $(OUTDIR) $(MINICARGO_FLAGS) test -e $@ RUSTC_ENV_VARS := CFG_COMPILER_HOST_TRIPLE=$(RUSTC_TARGET) @@ -66,11 +81,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 +109,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/test_smiri.sh b/test_smiri.sh new file mode 100755 index 00000000..63c94fa2 --- /dev/null +++ b/test_smiri.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -e +cd $(dirname $0) +make -f minicargo.mk MMIR=1 LIBS +./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 +./tools/bin/standalone_miri output-mmir/hello.mir -- cgit v1.2.3 From f2ba1740cf1570bc06ddf5472a7319fdbb5ff827 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 13:55:04 +0800 Subject: Standalone Miri - More implementation work --- tools/standalone_miri/Makefile | 1 + tools/standalone_miri/main.cpp | 51 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/tools/standalone_miri/Makefile b/tools/standalone_miri/Makefile index 94c89452..95e99c75 100644 --- a/tools/standalone_miri/Makefile +++ b/tools/standalone_miri/Makefile @@ -16,6 +16,7 @@ OBJS := main.o debug.o mir.o lex.o value.o module_tree.o hir_sim.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)%) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 384bc79e..86a213dd 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -1266,10 +1266,16 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar } } break; TU_ARM(se.src, DstMeta, re) { - LOG_TODO(stmt); + 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) { - LOG_TODO(stmt); + 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 @@ -1655,6 +1661,17 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab } } #else + // POSIX + else if( link_name == "sysconf" ) + { + auto name = args.at(0).read_i32(0); + LOG_DEBUG("FFI sysconf(" << name << ")"); + long val = sysconf(name); + auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv.write_usize(0, val); + return rv; + } +#endif // std C else if( link_name == "signal" ) { @@ -1663,17 +1680,33 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab rv.write_usize(0, 1); return rv; } - // POSIX - else if( link_name == "sysconf" ) + // - `void *memchr(const void *s, int c, size_t n);` + else if( link_name == "memchr" ) { - auto name = args.at(0).read_i32(0); - LOG_DEBUG("FFI sysconf(" << name << ")"); - long val = sysconf(name); + LOG_ASSERT(args.at(0).allocation.is_alloc(), ""); + //size_t ptr_space; + //void* ptr = args.at(0).read_pointer(0, ptr_space); + auto ptr_alloc = args.at(0).allocation.alloc().get_relocation(0); + void* ptr = ptr_alloc.alloc().data_ptr() + args.at(0).read_usize(0); + auto c = args.at(1).read_i32(0); + auto n = args.at(2).read_usize(0); + // TODO: Check range of `n` + + void* ret = memchr(ptr, c, n); + auto rv = Value(::HIR::TypeRef(RawType::USize)); - rv.write_usize(0, val); + rv.create_allocation(); + if( ret ) + { + rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast(ret) - static_cast(ptr) )); + rv.allocation.alloc().relocations.push_back({ 0, ptr_alloc }); + } + else + { + rv.write_usize(0, 0); + } return rv; } -#endif // Allocators! else { -- cgit v1.2.3 From d667b43bd5971f63d396d2a1a587743c3cfceb68 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 15:03:37 +0800 Subject: Standalone MIRI - De-duplicate some value code --- tools/standalone_miri/value.cpp | 82 +++++++++++++++++++------ tools/standalone_miri/value.hpp | 132 +++++++++++++++++++++------------------- 2 files changed, 133 insertions(+), 81 deletions(-) diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index beff8a38..af462e40 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -150,6 +150,68 @@ size_t AllocationPtr::get_size() const return os; } +uint64_t ValueCommon::read_usize(size_t ofs) const +{ + uint64_t v = 0; + this->read_bytes(ofs, &v, POINTER_SIZE); + return v; +} +void ValueCommon::write_usize(size_t ofs, uint64_t v) +{ + this->write_bytes(ofs, &v, POINTER_SIZE); +} +void* ValueCommon::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"); + } + out_is_mut = false; + out_size = 0; + return nullptr; + } + else + { + switch(reloc.get_ty()) + { + case AllocationPtr::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 AllocationPtr::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( static_cast(s.data() + ofs) ); + } + case AllocationPtr::Ty::Function: + LOG_FATAL("read_pointer w/ function"); + case AllocationPtr::Ty::FfiPointer: + 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 = 0; + out_is_mut = false; + return reloc.ffi().ptr_value /* + ofs */; + } + throw ""; + } +} + void Allocation::resize(size_t new_size) { @@ -371,10 +433,6 @@ 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) -{ - this->write_bytes(ofs, &v, POINTER_SIZE); -} ::std::ostream& operator<<(::std::ostream& os, const Allocation& x) { auto flags = os.flags(); @@ -651,10 +709,6 @@ void Value::write_value(size_t ofs, Value v) } } } -void Value::write_usize(size_t ofs, uint64_t v) -{ - this->write_bytes(ofs, &v, POINTER_SIZE); -} ::std::ostream& operator<<(::std::ostream& os, const Value& v) { @@ -775,15 +829,3 @@ uint64_t ValueRef::read_usize(size_t ofs) const this->read_bytes(ofs, &v, POINTER_SIZE); return v; } -uint64_t Value::read_usize(size_t ofs) const -{ - uint64_t v = 0; - this->read_bytes(ofs, &v, POINTER_SIZE); - return v; -} -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 fb5cc5ae..95f8b508 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -110,7 +110,60 @@ struct Relocation size_t slot_ofs; AllocationPtr backing_alloc; }; -class Allocation + +struct ValueCommon +{ + virtual AllocationPtr get_relocation(size_t ofs) const = 0; + virtual void read_bytes(size_t ofs, void* dst, size_t count) const = 0; + 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(v)); } + void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast(v)); } + void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast(v)); } + void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast(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(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(read_u8(ofs)); } + int16_t read_i16(size_t ofs) const { return static_cast(read_u16(ofs)); } + int32_t read_i32(size_t ofs) const { return static_cast(read_u32(ofs)); } + int64_t read_i64(size_t ofs) const { return static_cast(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(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; + } +}; + +class Allocation: + public ValueCommon { friend class AllocationPtr; size_t refcount; @@ -126,7 +179,7 @@ public: ::std::vector mask; ::std::vector relocations; - AllocationPtr get_relocation(size_t ofs) const { + AllocationPtr get_relocation(size_t ofs) const override { for(const auto& r : relocations) { if(r.slot_ofs == ofs) return r.backing_alloc; @@ -144,41 +197,15 @@ 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(v)); } - void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast(v)); } - void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast(v)); } - void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast(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(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(read_u8(ofs)); } - int16_t read_i16(size_t ofs) const { return static_cast(read_u16(ofs)); } - int32_t read_i32(size_t ofs) const { return static_cast(read_u32(ofs)); } - int64_t read_i64(size_t ofs) const { return static_cast(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(read_usize(ofs)); } + void write_bytes(size_t ofs, const void* src, size_t count) override; }; extern ::std::ostream& operator<<(::std::ostream& os, const Allocation& x); -struct Value +struct Value: + public ValueCommon { // If NULL, data is direct AllocationPtr allocation; @@ -197,46 +224,27 @@ struct Value void create_allocation(); size_t size() const { return allocation ? allocation.alloc().size() : direct_data.size; } + AllocationPtr get_relocation(size_t ofs) const override { + if( this->allocation && this->allocation.is_alloc() ) + return this->allocation.alloc().get_relocation(ofs); + else + return AllocationPtr(); + } + 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); - - // 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(v)); } - void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast(v)); } - void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast(v)); } - void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast(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(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(read_u8(ofs)); } - int16_t read_i16(size_t ofs) const { return static_cast(read_u16(ofs)); } - int32_t read_i32(size_t ofs) const { return static_cast(read_u32(ofs)); } - int64_t read_i64(size_t ofs) const { return static_cast(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(read_usize(ofs)); } + void write_bytes(size_t ofs, const void* src, size_t count) 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 + //:public ValueCommon { // Either an AllocationPtr, or a Value pointer AllocationPtr m_alloc; @@ -352,6 +360,8 @@ struct ValueRef m_value->read_bytes(m_offset + ofs, dst, size); } } + + // TODO: Figure out how to make this use `ValueCommon` when it can't write. 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; } -- cgit v1.2.3 From 835519441441dcff3bb39e9a82f433a37c61d6ef Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 17:54:27 +0800 Subject: Standalone MIRI - Get type for statics, add some pthread_* FFI stubs --- tools/standalone_miri/main.cpp | 43 +++++++++++++++++++++++++++-------- tools/standalone_miri/module_tree.cpp | 12 ++++++---- tools/standalone_miri/module_tree.hpp | 17 ++++++++------ 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 86a213dd..e3c7ab50 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -433,8 +433,9 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar 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()); + /*const*/ auto& s = modtree.get_static(e); + ty = s.ty; + return ValueRef(s.val, 0, s.val.size()); } break; TU_ARM(lv, Index, e) { auto idx = get_value_ref(*e.idx).read_usize(0); @@ -678,7 +679,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar for(const auto& stmt : bb.statements) { - LOG_DEBUG("BB" << bb_idx << "/" << (&stmt - bb.statements.data()) << ": " << stmt); + LOG_DEBUG("=== BB" << bb_idx << "/" << (&stmt - bb.statements.data()) << ": " << stmt); switch(stmt.tag()) { case ::MIR::Statement::TAGDEAD: throw ""; @@ -1424,7 +1425,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar } } - LOG_DEBUG("BB" << bb_idx << "/TERM: " << bb.terminator); + LOG_DEBUG("=== BB" << bb_idx << "/TERM: " << bb.terminator); switch(bb.terminator.tag()) { case ::MIR::Terminator::TAGDEAD: throw ""; @@ -1522,7 +1523,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar 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)"); const auto& fcn_alloc_ptr = alloc_ptr.alloc().get_relocation(v.m_offset); - LOG_ASSERT(fcn_alloc_ptr, "Calling value with no relocation"); + if( !fcn_alloc_ptr ) + LOG_FATAL("Calling value with no relocation - " << v); LOG_ASSERT(fcn_alloc_ptr.get_ty() == AllocationPtr::Ty::Function, "Calling value that isn't a function pointer"); fcn_p = &fcn_alloc_ptr.fcn(); } @@ -1671,6 +1673,30 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab rv.write_usize(0, val); return rv; } + else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } + else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } + else if( link_name == "pthread_condattr_init" || link_name == "pthread_condattr_destroy" || link_name == "pthread_condattr_setclock" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } + else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } #endif // std C else if( link_name == "signal" ) @@ -1684,15 +1710,12 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab else if( link_name == "memchr" ) { LOG_ASSERT(args.at(0).allocation.is_alloc(), ""); - //size_t ptr_space; - //void* ptr = args.at(0).read_pointer(0, ptr_space); auto ptr_alloc = args.at(0).allocation.alloc().get_relocation(0); - void* ptr = ptr_alloc.alloc().data_ptr() + args.at(0).read_usize(0); auto c = args.at(1).read_i32(0); auto n = args.at(2).read_usize(0); - // TODO: Check range of `n` + const void* ptr = args.at(0).read_pointer_const(0, n); - void* ret = memchr(ptr, c, n); + const void* ret = memchr(ptr, c, n); auto rv = Value(::HIR::TypeRef(RawType::USize)); rv.create_allocation(); diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index d62695d1..d6c7dcec 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -154,10 +154,12 @@ bool Parser::parse_one() } lex.check_consume(';'); - Value val = Value(ty); - val.write_bytes(0, data.data(), data.size()); + Static s; + s.val = Value(ty); + s.val.write_bytes(0, data.data(), data.size()); + s.ty = ty; - tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(val) )); + tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(s) )); } else if( lex.consume_if("type") ) { @@ -1311,7 +1313,7 @@ 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()) @@ -1321,7 +1323,7 @@ Value& ModuleTree::get_static(const ::HIR::Path& p) } 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()) 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 `::""::` ::std::map<::HIR::GenericPath, ::std::unique_ptr> 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); -- cgit v1.2.3 From 11574b8b30b87fdc130f4e276839eda52860582b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 18:21:36 +0800 Subject: Standalone MIRI - Better handling of statics --- tools/standalone_miri/main.cpp | 23 ++++++++++++++++++++--- tools/standalone_miri/module_tree.cpp | 19 ++++++++++++------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index e3c7ab50..c9cc7f38 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -627,9 +627,18 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar 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) ) { + ty = ::HIR::TypeRef(RawType::Function); return Value::new_fnptr(ce); } - LOG_TODO("Constant::ItemAddr - statics?"); + if( const auto* s = modtree.get_static_opt(ce) ) { + ty = s->ty; + ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); + Value val = Value(ty); + val.write_usize(0, 0); + val.allocation.alloc().relocations.push_back(Relocation { 0, s->val.allocation }); + return val; + } + LOG_TODO("Constant::ItemAddr - " << ce << " - not found"); } break; } throw ""; @@ -1510,6 +1519,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar } else { + AllocationPtr fcn_alloc_ptr; const ::HIR::Path* fcn_p; if( te.fcn.is_Path() ) { fcn_p = &te.fcn.as_Path(); @@ -1517,12 +1527,13 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar 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(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)"); - const auto& fcn_alloc_ptr = alloc_ptr.alloc().get_relocation(v.m_offset); + fcn_alloc_ptr = alloc_ptr.alloc().get_relocation(v.m_offset); if( !fcn_alloc_ptr ) LOG_FATAL("Calling value with no relocation - " << v); LOG_ASSERT(fcn_alloc_ptr.get_ty() == AllocationPtr::Ty::Function, "Calling value that isn't a function pointer"); @@ -1697,6 +1708,12 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab rv.write_i32(0, 0); return rv; } + else if( link_name == "pthread_key_create" || link_name == "pthread_key_delete" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } #endif // std C else if( link_name == "signal" ) @@ -1761,7 +1778,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, const ::std::string& name, cons const auto& ty = ty_params.tys.at(0); alloc.alloc().write_value(ofs, ::std::move(data_val)); } - else if( name == "atomic_load" ) + 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"); diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index d6c7dcec..f6b681cf 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -121,6 +121,15 @@ bool Parser::parse_one() 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('}') ) @@ -135,12 +144,13 @@ bool Parser::parse_one() if( lex.next() == TokenClass::String ) { auto reloc_str = ::std::move(lex.consume().strval); - // TODO: Add relocation + // TODO: Figure out how to create this allocation... + //s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_string(reloc_str) }); } else if( lex.next() == "::" ) { auto reloc_path = parse_path(); - // TODO: Add relocation + s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_fcn(reloc_path) }); } else { @@ -154,11 +164,6 @@ bool Parser::parse_one() } lex.check_consume(';'); - Static s; - s.val = Value(ty); - s.val.write_bytes(0, data.data(), data.size()); - s.ty = ty; - tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(s) )); } else if( lex.consume_if("type") ) -- cgit v1.2.3 From 6a56c4c2fb5be1fc6dae05da6bff936ce75553de Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 19:03:55 +0800 Subject: Codegen MMIR - Emit vtables (only partially complete) --- src/trans/codegen_mmir.cpp | 142 +++++++++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 38 deletions(-) diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index faa3598d..db538842 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -605,47 +605,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& 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 +880,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; -- cgit v1.2.3 From 5de0393d29ac0e7eb3ede52fe665fd49ac412f21 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 19:04:09 +0800 Subject: MIR Cleanup - Remove cast of PhantomData --- src/mir/cleanup.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) 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, -- cgit v1.2.3 From d8928895e318b026f106a30f145d6a41be74cb0f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 19:05:54 +0800 Subject: Standalone MIRI - Fiddling around --- tools/standalone_miri/main.cpp | 14 +++++++++----- tools/standalone_miri/module_tree.cpp | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index c9cc7f38..b7f62252 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -378,6 +378,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar return ret; } + // TODO: Recursion limit. + TRACE_FUNCTION_R(path, path << " = " << ret); for(size_t i = 0; i < args.size(); i ++) { @@ -809,11 +811,13 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar 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::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) diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index f6b681cf..a75cfa8f 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -147,13 +147,14 @@ bool Parser::parse_one() // TODO: Figure out how to create this allocation... //s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_string(reloc_str) }); } - else if( lex.next() == "::" ) + else if( lex.next() == "::" || lex.next() == "<" ) { auto reloc_path = parse_path(); s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_fcn(reloc_path) }); } else { + LOG_FATAL(lex << "Unexepcted token " << lex.next() << " in relocation value"); throw "ERROR"; } if( ! lex.consume_if(',') ) { -- cgit v1.2.3 From d14ab6eae9abd88ab4e26d7c7fd2f91d48d1a10f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 21:06:49 +0800 Subject: Standalone MIRI - TLS and some other messing about --- src/trans/codegen_mmir.cpp | 2 +- tools/standalone_miri/main.cpp | 144 +++++++++++++++++++++++++++++++++------- tools/standalone_miri/value.cpp | 53 ++++++++++++++- tools/standalone_miri/value.hpp | 86 +++++++++++++++--------- 4 files changed, 228 insertions(+), 57 deletions(-) diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index db538842..19574814 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): i32 {\n"; auto c_start_path = m_resolve.m_crate.get_lang_item_path_opt("mrustc-start"); if( c_start_path == ::HIR::SimplePath() ) { diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index b7f62252..1b33087a 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -19,9 +19,31 @@ struct ProgramOptions int parse(int argc, const char* argv[]); }; -Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector args); -Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& abi, ::std::vector args); -Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector args); +struct ThreadState +{ + static unsigned s_next_tls_key; + unsigned call_stack_depth; + ::std::vector 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 }; + } +}; +unsigned ThreadState::s_next_tls_key = 1; + +Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, ::std::vector args); +Value MIRI_Invoke_Extern(ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector args); +Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector args); int main(int argc, const char* argv[]) { @@ -36,20 +58,21 @@ int main(int argc, const char* argv[]) tree.load_file(opts.infile); - auto val_argc = Value( ::HIR::TypeRef{RawType::I32} ); + auto val_argc = Value( ::HIR::TypeRef{RawType::ISize} ); ::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_argc.write_bytes(0, "\0\0\0\0\0\0\0", 8); val_argv.write_bytes(0, "\0\0\0\0\0\0\0", argv_ty.get_size()); try { + ThreadState ts; ::std::vector 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) ); + auto rv = MIRI_Invoke( tree, ts, tree.find_lang_item("start"), ::std::move(args) ); ::std::cout << rv << ::std::endl; } catch(const DebugExceptionTodo& /*e*/) @@ -291,7 +314,7 @@ struct Ops { namespace { - void drop_value(ModuleTree& modtree, Value ptr, const ::HIR::TypeRef& ty) + void drop_value(ModuleTree& modtree, ThreadState& thread, Value ptr, const ::HIR::TypeRef& ty) { if( ty.wrappers.empty() ) { @@ -301,7 +324,7 @@ namespace { LOG_DEBUG("Drop - " << ty); - MIRI_Invoke(modtree, ty.composite_type->drop_glue, { ptr }); + MIRI_Invoke(modtree, thread, ty.composite_type->drop_glue, { ptr }); } else { @@ -338,7 +361,7 @@ namespace } -Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector args) +Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, ::std::vector args) { Value ret; @@ -373,17 +396,22 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar if( fcn.external.link_name != "" ) { // External function! - ret = MIRI_Invoke_Extern(fcn.external.link_name, fcn.external.link_abi, ::std::move(args)); + ret = MIRI_Invoke_Extern(thread, fcn.external.link_name, fcn.external.link_abi, ::std::move(args)); LOG_DEBUG(path << " = " << ret); return ret; } - // TODO: Recursion limit. + // Recursion limit. + if( thread.call_stack_depth > 40 ) { + LOG_ERROR("Recursion limit exceeded"); + } + auto _ = thread.enter_function(); TRACE_FUNCTION_R(path, path << " = " << ret); for(size_t i = 0; i < args.size(); i ++) { LOG_DEBUG("- Argument(" << i << ") = " << args[i]); + // TODO: Check argument sizes against prototype? } ret = Value(fcn.ret_ty == RawType::Unreachable ? ::HIR::TypeRef() : fcn.ret_ty); @@ -489,7 +517,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar ::HIR::TypeRef ptr_ty; auto val = get_value_and_type(*e.val, ptr_ty); ty = ptr_ty.get_inner(); - LOG_DEBUG("val = " << val); + 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); @@ -500,7 +528,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar 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"); + // NOTE: No alloc can happen when dereferencing a zero-sized pointer if( alloc.is_alloc() ) { LOG_DEBUG("> " << lv << " alloc=" << alloc.alloc()); @@ -517,15 +545,26 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar meta_val = ::std::make_shared( 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; + if( alloc ) + { + LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs); + size = alloc.get_size() - ofs; + } + else + { + size = 0; + } } 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; @@ -709,7 +748,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar ::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( !alloc && src_base_value.m_value ) { if( !src_base_value.m_value->allocation ) { @@ -1422,7 +1461,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar ptr_val.write_usize(0, ofs); ptr_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) }); - drop_value(modtree, ptr_val, ty); + drop_value(modtree, thread, ptr_val, ty); // TODO: Clear validity on the entire inner value. //alloc.mark_as_freed(); } @@ -1515,11 +1554,12 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar for(const auto& a : te.args) { sub_args.push_back( state.param_to_value(a) ); + LOG_DEBUG("#" << (sub_args.size() - 1) << " " << sub_args.back()); } 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))); + state.write_lvalue(te.ret_val, MIRI_Invoke_Intrinsic(modtree, thread, fe.name, fe.params, ::std::move(sub_args))); } else { @@ -1534,7 +1574,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar LOG_DEBUG("> Indirect call " << v); // TODO: Assert type // TODO: Assert offset/content. - assert(v.read_usize(v.m_offset) == 0); + assert(v.read_usize(0) == 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)"); fcn_alloc_ptr = alloc_ptr.alloc().get_relocation(v.m_offset); @@ -1545,7 +1585,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector ar } LOG_DEBUG("Call " << *fcn_p); - auto v = MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args)); + auto v = MIRI_Invoke(modtree, thread, *fcn_p, ::std::move(sub_args)); LOG_DEBUG(te.ret_val << " = " << v << " (resume " << path << ")"); state.write_lvalue(te.ret_val, ::std::move(v)); } @@ -1562,7 +1602,7 @@ extern "C" { long sysconf(int); } -Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& abi, ::std::vector args) +Value MIRI_Invoke_Extern(ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector args) { if( link_name == "__rust_allocate" ) { @@ -1712,7 +1752,45 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab rv.write_i32(0, 0); return rv; } - else if( link_name == "pthread_key_create" || link_name == "pthread_key_delete" ) + else if( link_name == "pthread_key_create" ) + { + size_t size; + 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 ); + + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } + 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 < thread.tls_values.size() ? thread.tls_values[key] : 0; + + auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv.write_usize(0, v); + return rv; + } + 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 >= thread.tls_values.size() ) { + thread.tls_values.resize(key+1); + } + thread.tls_values[key] = v; + + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } + else if( link_name == "pthread_key_delete" ) { auto rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); @@ -1758,7 +1836,7 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab } throw ""; } -Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector args) +Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector args) { Value rv; TRACE_FUNCTION_R(name, rv); @@ -1798,6 +1876,24 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, const ::std::string& name, cons const auto& ty = ty_params.tys.at(0); rv = alloc.alloc().read_value(ofs, ty.get_size()); } + 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(1); + rv = Value::with_size( ty_T.get_size() + 1, false ); + rv.write_value(0, data_ref.read_value(0, old_v.size())); + if( data_ref.compare(old_v.data_ptr(), old_v.size()) == 0 ) { + 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 ); + } + return rv; + } else if( name == "transmute" ) { // Transmute requires the same size, so just copying the value works @@ -1919,7 +2015,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, const ::std::string& name, cons auto ptr = val.read_value(0, POINTER_SIZE);; for(size_t i = 0; i < item_count; i ++) { - drop_value(modtree, ptr, ity); + drop_value(modtree, thread, ptr, ity); ptr.write_usize(0, ptr.read_usize(0) + item_size); } } diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index af462e40..468425e9 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -211,6 +211,20 @@ void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& throw ""; } } +ValueRef ValueCommon::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) @@ -231,7 +245,7 @@ void Allocation::check_bytes_valid(size_t ofs, size_t size) const { if( !(this->mask[i/8] & (1 << i%8)) ) { - ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl; + LOG_ERROR("Invalid bytes in value"); throw "ERROR"; } } @@ -749,7 +763,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) { case AllocationPtr::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++) @@ -823,6 +837,41 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) return os; } +Value ValueRef::read_value(size_t ofs, size_t size) const +{ + 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 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(), ""); + 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); + } +} +bool ValueRef::compare(const void* other, size_t other_len) const +{ + check_bytes_valid(0, other_len); + return ::std::memcmp(data_ptr(), other, other_len) == 0; +} uint64_t ValueRef::read_usize(size_t ofs) const { uint64_t v = 0; diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 95f8b508..2b3bd4e6 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -15,6 +15,7 @@ namespace HIR { } class Allocation; struct Value; +struct ValueRef; struct FFIPointer { @@ -160,6 +161,8 @@ struct ValueCommon //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: @@ -223,6 +226,8 @@ struct Value: void create_allocation(); size_t size() const { return allocation ? allocation.alloc().size() : direct_data.size; } + const uint8_t* data_ptr() const { return allocation ? allocation.alloc().data_ptr() : direct_data.data; } + uint8_t* data_ptr() { return allocation ? allocation.alloc().data_ptr() : direct_data.data; } AllocationPtr get_relocation(size_t ofs) const override { if( this->allocation && this->allocation.is_alloc() ) @@ -259,20 +264,23 @@ struct ValueRef 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 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"; + } } } ValueRef(Value& val): @@ -294,7 +302,7 @@ struct ValueRef else return AllocationPtr(); } - else if( m_value->allocation ) + else if( m_value && m_value->allocation ) { if( m_value->allocation.is_alloc() ) return m_value->allocation.alloc().get_relocation(ofs); @@ -306,9 +314,30 @@ struct ValueRef return AllocationPtr(); } } - Value read_value(size_t ofs, size_t size) const { + 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 AllocationPtr::Ty::Allocation: + return m_alloc.alloc().data_ptr() + m_offset; + break; + case AllocationPtr::Ty::StdString: + return reinterpret_cast(m_alloc.str().data() + m_offset); + default: + throw "TODO"; + } + } + else if( m_value ) { + return m_value->data_ptr() + m_offset; + } + else { + return nullptr; + } + } + 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); @@ -316,26 +345,22 @@ struct ValueRef 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(), ""); + m_alloc.alloc().read_bytes(m_offset + ofs, dst, size); + break; + case AllocationPtr::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); @@ -345,11 +370,10 @@ struct ValueRef switch(m_alloc.get_ty()) { case AllocationPtr::Ty::Allocation: - m_alloc.alloc().read_bytes(m_offset + ofs, dst, size); + m_alloc.alloc().check_bytes_valid(m_offset + ofs, size); break; case AllocationPtr::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 - " << ); @@ -357,10 +381,12 @@ struct ValueRef } } else { - m_value->read_bytes(m_offset + ofs, dst, size); + m_value->check_bytes_valid(m_offset + ofs, size); } } + bool compare(const void* other, size_t other_len) const; + // TODO: Figure out how to make this use `ValueCommon` when it can't write. 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; } -- cgit v1.2.3 From 561d2ddc8e67277dbe12216f9a365d65ec3f5c2c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2018 22:09:41 +0800 Subject: Trans - Support NonZero optimisation for Box --- src/trans/codegen_c.cpp | 6 ++++++ src/trans/target.cpp | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 5df20334..59687636 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1127,6 +1127,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 diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 81dc8c0c..7aa46b35 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -876,6 +876,13 @@ namespace { return true; } } + // Handle the NonZero lang item (TODO: Cleaner?) + 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 +926,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) -- cgit v1.2.3 From 9aae4d5af2da15c8ff40966bed6faeef7126f7a4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 08:25:04 +0800 Subject: Codegen MMIR - Struct constructors --- src/trans/codegen_mmir.cpp | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 19574814..dd6f1468 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -433,6 +433,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 +489,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"; -- cgit v1.2.3 From 9f8469d5145ea51f2d4b2b9d1eb32d1029cfbeb5 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 08:54:44 +0800 Subject: Standalone MIRI - Atomic add, catch_panic --- tools/standalone_miri/main.cpp | 94 ++++++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 22 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 1b33087a..e5ef9c15 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -42,7 +42,7 @@ struct ThreadState unsigned ThreadState::s_next_tls_key = 1; Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, ::std::vector args); -Value MIRI_Invoke_Extern(ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector args); +Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector args); Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector args); int main(int argc, const char* argv[]) @@ -98,7 +98,7 @@ public: 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; + virtual void write_to_value(ValueCommon& tgt, size_t ofs) const = 0; template const T& check(const char* opname) const @@ -157,14 +157,14 @@ struct PrimitiveUInt: struct PrimitiveU64: public PrimitiveUInt { PrimitiveU64(uint64_t v): PrimitiveUInt(v) {} - void write_to_value(Value& tgt, size_t ofs) const override { + void write_to_value(ValueCommon& tgt, size_t ofs) const override { tgt.write_u64(ofs, this->v); } }; struct PrimitiveU32: public PrimitiveUInt { PrimitiveU32(uint32_t v): PrimitiveUInt(v) {} - void write_to_value(Value& tgt, size_t ofs) const override { + void write_to_value(ValueCommon& tgt, size_t ofs) const override { tgt.write_u32(ofs, this->v); } }; @@ -218,14 +218,14 @@ struct PrimitiveSInt: struct PrimitiveI64: public PrimitiveSInt { PrimitiveI64(int64_t v): PrimitiveSInt(v) {} - void write_to_value(Value& tgt, size_t ofs) const override { + void write_to_value(ValueCommon& tgt, size_t ofs) const override { tgt.write_i64(ofs, this->v); } }; struct PrimitiveI32: public PrimitiveSInt { PrimitiveI32(int32_t v): PrimitiveSInt(v) {} - void write_to_value(Value& tgt, size_t ofs) const override { + void write_to_value(ValueCommon& tgt, size_t ofs) const override { tgt.write_i32(ofs, this->v); } }; @@ -340,23 +340,30 @@ namespace // No destructor } } - else if( ty.wrappers[0].type == TypeWrapper::Ty::Borrow ) + else { - if( ty.wrappers[0].size == static_cast(::HIR::BorrowType::Move) ) - { - LOG_TODO("Drop - " << ty << " - dereference and go to inner"); - // TODO: Clear validity on the entire inner value. - } - else + switch( ty.wrappers[0].type ) { + case TypeWrapper::Ty::Borrow: + if( ty.wrappers[0].size == static_cast(::HIR::BorrowType::Move) ) + { + LOG_TODO("Drop - " << ty << " - dereference and go to inner"); + // TODO: Clear validity on the entire inner value. + } + else + { + // No destructor + } + break; + case TypeWrapper::Ty::Pointer: // No destructor + break; + // TODO: Arrays + default: + LOG_TODO("Drop - " << ty << " - array?"); + break; } } - // TODO: Arrays - else - { - LOG_TODO("Drop - " << ty << " - array?"); - } } } @@ -396,7 +403,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: if( fcn.external.link_name != "" ) { // External function! - ret = MIRI_Invoke_Extern(thread, fcn.external.link_name, fcn.external.link_abi, ::std::move(args)); + ret = MIRI_Invoke_Extern(modtree, thread, fcn.external.link_name, fcn.external.link_abi, ::std::move(args)); LOG_DEBUG(path << " = " << ret); return ret; } @@ -1515,7 +1522,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: // Save as the default, error for multiple defaults if( default_target != SIZE_MAX ) { - LOG_FATAL("Two variants with no tag in Switch"); + LOG_FATAL("Two variants with no tag in Switch - " << ty); } default_target = i; } @@ -1602,7 +1609,7 @@ extern "C" { long sysconf(int); } -Value MIRI_Invoke_Extern(ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector args) +Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector args) { if( link_name == "__rust_allocate" ) { @@ -1654,6 +1661,27 @@ Value MIRI_Invoke_Extern(ThreadState& thread, const ::std::string& link_name, co // Just let it drop. return 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 sub_args; + sub_args.push_back( ::std::move(arg) ); + + // TODO: Catch the panic out of this. + MIRI_Invoke(modtree, thread, fcn_path, ::std::move(sub_args)); + + auto rv = Value(::HIR::TypeRef(RawType::U32)); + rv.write_u32(0,0); + return rv; + } + else if( link_name == "__rust_start_panic" ) + { + LOG_TODO("__rust_start_panic"); + } #ifdef _WIN32 // WinAPI functions used by libstd else if( link_name == "AddVectoredExceptionHandler" ) @@ -1870,12 +1898,33 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st 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 lock the allocation. - // 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 == "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).allocation.alloc().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_cxchg" ) { const auto& ty_T = ty_params.tys.at(0); @@ -2112,6 +2161,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st { case AllocationPtr::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 AllocationPtr::Ty::StdString: -- cgit v1.2.3 From ac6f3ffba823e539c4c9afd93b7edf7122f463cc Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 09:27:13 +0800 Subject: Standalone MIRI - Better vtable handling, fix to offset with null pointers --- tools/standalone_miri/hir_sim.cpp | 30 +++++++++++-------- tools/standalone_miri/hir_sim.hpp | 6 ++-- tools/standalone_miri/main.cpp | 31 +++++++++---------- tools/standalone_miri/module_tree.cpp | 56 +++++++++++++++++------------------ 4 files changed, 65 insertions(+), 58 deletions(-) diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 604f65a4..f3b4d400 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -166,32 +166,34 @@ const HIR::TypeRef* HIR::TypeRef::get_usized_type(size_t& running_inner_size) co return nullptr; } } -const HIR::TypeRef* HIR::TypeRef::get_meta_type() 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; - case RawType::TraitObject: - LOG_TODO("get_meta_type on TraitObject - " << *this); + return TypeRef(RawType::Unreachable); + return this->composite_type->dst_meta; + case RawType::TraitObject: { + auto rv = ::HIR::TypeRef( this->composite_type ); + rv.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, static_cast(BorrowType::Shared) }); + return rv; + } 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; + return TypeRef(RawType::USize); } else { - return nullptr; + return TypeRef(RawType::Unreachable); } } @@ -305,7 +307,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 +391,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..1dc9bcc4 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 { @@ -120,7 +120,7 @@ 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; + TypeRef get_meta_type() const; TypeRef get_inner() const; TypeRef wrap(TypeWrapper::Ty ty, size_t size) const; TypeRef get_field(size_t idx, size_t& ofs) const; diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index e5ef9c15..16cfd972 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -503,7 +503,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: 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() ) + 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(); @@ -542,12 +542,12 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: } size_t size; - const auto* meta_ty = ty.get_meta_type(); + const auto meta_ty = ty.get_meta_type(); ::std::shared_ptr meta_val; // If the type has metadata, store it. - if( meta_ty ) + if( meta_ty != RawType::Unreachable ) { - auto meta_size = meta_ty->get_size(); + 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( val.read_value(POINTER_SIZE, meta_size) ); @@ -768,14 +768,14 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: else LOG_DEBUG("- alloc=" << alloc); size_t ofs = src_base_value.m_offset; - const auto* meta = src_ty.get_meta_type(); + 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(re.type) }); new_val = Value(src_ty); // ^ Pointer value new_val.write_usize(0, ofs); - if( meta ) + 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); @@ -1460,7 +1460,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: alloc = AllocationPtr(v.m_value->allocation); } size_t ofs = v.m_offset; - assert(!ty.get_meta_type()); + assert(ty.get_meta_type() == RawType::Unreachable); auto ptr_ty = ty.wrap(TypeWrapper::Ty::Borrow, 2); @@ -1954,20 +1954,21 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st } else if( name == "offset" ) { - auto ptr_val = ::std::move(args.at(0)); + 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 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(); + auto new_ofs = ptr_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); + rv = ::std::move(args.at(0)); + rv.write_usize(0, new_ofs); + if( ptr_alloc ) { + rv.allocation.alloc().relocations.push_back({ 0, ptr_alloc }); + } } // effectively ptr::write else if( name == "move_val_init" ) @@ -2008,7 +2009,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st size_t fixed_size = 0; if( const auto* ity = ty.get_usized_type(fixed_size) ) { - const auto& meta_ty = *ty.get_meta_type(); + 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() ) diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index a75cfa8f..fdc8f587 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -32,6 +32,8 @@ 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) @@ -1130,19 +1132,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 {}); - 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('[') ) { @@ -1155,7 +1146,6 @@ RawType Parser::parse_core_type() } else { - // TODO: How to handle arrays? rv.wrappers.insert( rv.wrappers.begin(), { TypeWrapper::Ty::Slice, 0 }); } lex.check_consume(']'); @@ -1196,19 +1186,7 @@ RawType Parser::parse_core_type() 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 {}); - 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" ) { @@ -1282,8 +1260,17 @@ RawType Parser::parse_core_type() 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 ) { @@ -1295,6 +1282,19 @@ RawType Parser::parse_core_type() throw "ERROR"; } } +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 {}); + 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 { -- cgit v1.2.3 From d3334162fa91fe6fd5d02912d9f82794306e646a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 09:54:54 +0800 Subject: Standalone MIRI - Create allocations for static data --- tools/standalone_miri/module_tree.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index fdc8f587..c70f17dd 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -146,8 +146,11 @@ bool Parser::parse_one() if( lex.next() == TokenClass::String ) { auto reloc_str = ::std::move(lex.consume().strval); - // TODO: Figure out how to create this allocation... - //s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_string(reloc_str) }); + + auto a = Allocation::new_alloc( reloc_str.size() ); + //a.alloc().set_tag(); + a.alloc().write_bytes(0, reloc_str.data(), reloc_str.size()); + s.val.allocation.alloc().relocations.push_back({ ofs, ::std::move(a) }); } else if( lex.next() == "::" || lex.next() == "<" ) { -- cgit v1.2.3 From c7b3036cefcd0dc412cb400455324d7ca8cd518e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 09:55:13 +0800 Subject: Standalone MIRI - memrchr and better null checking --- tools/standalone_miri/main.cpp | 22 ++++++++++++++++++++++ tools/standalone_miri/value.cpp | 3 +++ 2 files changed, 25 insertions(+) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 16cfd972..4ee503d3 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -1857,6 +1857,28 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: } return rv; } + 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); + + auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv.create_allocation(); + if( ret ) + { + rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast(ret) - static_cast(ptr) )); + rv.allocation.alloc().relocations.push_back({ 0, ptr_alloc }); + } + else + { + rv.write_usize(0, 0); + } + return rv; + } // Allocators! else { diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 468425e9..db352019 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -169,6 +169,9 @@ void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& 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; -- cgit v1.2.3 From 51e08ea81248930fdaf94acb4d893e8a47f406f2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 10:37:05 +0800 Subject: Standalone MIRI - Misc cleanups --- tools/standalone_miri/main.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 4ee503d3..d210849c 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -674,7 +674,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: } 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) ) { + if( /*const auto* fn =*/ modtree.get_function_opt(ce) ) { ty = ::HIR::TypeRef(RawType::Function); return Value::new_fnptr(ce); } @@ -769,7 +769,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: 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(); + //bool is_slice_like = src_ty.has_slice_meta(); src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast(re.type) }); new_val = Value(src_ty); @@ -1205,11 +1205,13 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: 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(shift), re.op)); break; case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast(shift), re.op)); break; case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast(shift), re.op)); break; case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast(shift), re.op)); break; case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast(shift), re.op)); break; + // TODO: Is signed allowed? default: LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); } @@ -1222,24 +1224,27 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: 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(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(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(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; - case RawType::I32: - new_val.write_i32( 0, static_cast(Ops::do_bitwise(v_l.read_i32(0), v_r.read_i32(0), re.op)) ); - break; default: LOG_TODO("BinOp bitwise - " << se.src << " w/ " << ty_l); } @@ -1276,20 +1281,26 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: 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: @@ -1320,7 +1331,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: new_val.write_isize( 0, -v.read_isize(0) ); break; default: - LOG_TODO("UniOp::INV - w/ type " << ty); + LOG_ERROR("UniOp::INV not valid on type " << ty); } break; } @@ -1474,7 +1485,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: } } break; TU_ARM(stmt, SetDropFlag, se) { - bool val = (se.other == ~0 ? false : state.drop_flags.at(se.other)) != se.new_val; + bool val = (se.other == ~0u ? false : state.drop_flags.at(se.other)) != se.new_val; LOG_DEBUG("- " << val); state.drop_flags.at(se.idx) = val; } break; @@ -1782,7 +1793,6 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: } else if( link_name == "pthread_key_create" ) { - size_t size; auto key_ref = args.at(0).read_pointer_valref_mut(0, 4); auto key = ThreadState::s_next_tls_key ++; @@ -1907,7 +1917,6 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st // 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" || name == "atomic_load_relaxed" ) @@ -2007,7 +2016,6 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st 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()); } -- cgit v1.2.3 From 689722fa920cfa74880922ac626cc935b202acc4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 14:08:55 +0800 Subject: Standalone MIRI - Shallow drops and better tracing --- tools/standalone_miri/main.cpp | 76 ++++++++++++++++++++++++++++++----- tools/standalone_miri/module_tree.cpp | 2 +- tools/standalone_miri/value.cpp | 52 ++++++++++++++++-------- tools/standalone_miri/value.hpp | 11 +++-- 4 files changed, 109 insertions(+), 32 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index d210849c..97ca8e6f 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -314,8 +314,22 @@ struct Ops { namespace { - void drop_value(ModuleTree& modtree, ThreadState& thread, Value ptr, const ::HIR::TypeRef& ty) + void drop_value(ModuleTree& modtree, ThreadState& thread, Value ptr, const ::HIR::TypeRef& ty, bool is_shallow=false) { + if( is_shallow ) + { + // HACK: Only works for Box 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 ; + } if( ty.wrappers.empty() ) { if( ty.inner_type == RawType::Composite ) @@ -1479,7 +1493,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: ptr_val.write_usize(0, ofs); ptr_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) }); - drop_value(modtree, thread, ptr_val, ty); + // TODO: Shallow drop + drop_value(modtree, thread, ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW); // TODO: Clear validity on the entire inner value. //alloc.mark_as_freed(); } @@ -1618,6 +1633,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: extern "C" { long sysconf(int); + ssize_t write(int, const void*, size_t); } Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector args) @@ -1661,14 +1677,12 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: 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_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(); - // TODO: Figure out how to prevent this ever being written again. - //alloc.mark_as_freed(); - for(auto& v : alloc.mask) - v = 0; + alloc.mark_as_freed(); // Just let it drop. return Value(); } @@ -1693,6 +1707,10 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: { 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" ) @@ -1758,6 +1776,18 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: } #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); + + auto rv = Value(::HIR::TypeRef(RawType::ISize)); + rv.write_isize(0, val); + return rv; + } else if( link_name == "sysconf" ) { auto name = args.at(0).read_i32(0); @@ -1767,7 +1797,7 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: rv.write_usize(0, val); return rv; } - else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" ) + else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" || link_name == "pthread_mutex_destroy" ) { auto rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); @@ -1902,7 +1932,11 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st TRACE_FUNCTION_R(name, rv); for(const auto& a : args) LOG_DEBUG("#" << (&a - args.data()) << ": " << a); - if( name == "atomic_store" ) + if( name == "atomic_fence" || name == "atomic_fence_acq" ) + { + return Value(); + } + else if( name == "atomic_store" ) { auto& ptr_val = args.at(0); auto& data_val = args.at(1); @@ -1956,6 +1990,27 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st 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).allocation.alloc().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_cxchg" ) { const auto& ty_T = ty_params.tys.at(0); @@ -2086,13 +2141,14 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st case TypeWrapper::Ty::Pointer: break; case TypeWrapper::Ty::Borrow: + // TODO: Only &move has a destructor 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);; + auto ptr = val.read_value(0, POINTER_SIZE); for(size_t i = 0; i < item_count; i ++) { drop_value(modtree, thread, ptr, ity); @@ -2101,7 +2157,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st } else { - LOG_TODO("drop_in_place - " << ty); + drop_value(modtree, thread, val, ty); } } // ---------------------------------------------------------------- diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index c70f17dd..88d8ff88 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -675,7 +675,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; diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index db352019..cdace6e2 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -232,6 +232,8 @@ ValueRef ValueCommon::read_pointer_valref_mut(size_t rd_ofs, size_t 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); @@ -246,9 +248,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))) ) { - LOG_ERROR("Invalid bytes in value"); + LOG_ERROR("Invalid bytes in value - " << ofs << "+" << size << " - " << *this); throw "ERROR"; } } @@ -258,14 +260,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) { @@ -292,14 +298,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.alloc().mask[i/8] |= set_mask; } } } @@ -315,21 +319,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 ; @@ -352,6 +358,11 @@ 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(); @@ -416,8 +427,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"; @@ -459,7 +477,7 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count) 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]; } diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 2b3bd4e6..aa41b838 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -171,6 +171,7 @@ class Allocation: friend class AllocationPtr; size_t refcount; // TODO: Read-only flag? + bool is_freed = false; public: static AllocationPtr new_alloc(size_t size); @@ -189,10 +190,12 @@ public: } return AllocationPtr(); } - //void mark_as_freed() { - // for(auto& v : mask) - // v = 0; - //} + void mark_as_freed() { + is_freed = true; + relocations.clear(); + for(auto& v : mask) + v = 0; + } void resize(size_t new_size); -- cgit v1.2.3 From 872827f5d8db975f41eabe1ec1048e50b3bc166f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 17:00:44 +0800 Subject: Standalone MIRI - Working hello.rs --- tools/standalone_miri/main.cpp | 35 ++++++++++++++++++++++++++++++++--- tools/standalone_miri/module_tree.cpp | 4 ++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 97ca8e6f..bd86967c 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -1803,6 +1803,12 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: rv.write_i32(0, 0); return rv; } + else if( link_name == "pthread_rwlock_rdlock" ) + { + auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + return rv; + } else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" ) { auto rv = Value(::HIR::TypeRef(RawType::I32)); @@ -1932,7 +1938,20 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st TRACE_FUNCTION_R(name, rv); for(const auto& a : args) LOG_DEBUG("#" << (&a - args.data()) << ": " << a); - if( name == "atomic_fence" || name == "atomic_fence_acq" ) + if( name == "type_id" ) + { + const auto& ty_T = ty_params.tys.at(0); + static ::std::vector 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" ) { return Value(); } @@ -2011,16 +2030,26 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st 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(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())); - if( data_ref.compare(old_v.data_ptr(), old_v.size()) == 0 ) { + 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 ); } diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 88d8ff88..ad41b33a 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -102,6 +102,7 @@ bool Parser::parse_one() auto abi = ::std::move(lex.check_consume(TokenClass::String).strval); lex.check_consume(';'); + LOG_DEBUG("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}, {} }) ); } @@ -109,6 +110,7 @@ bool Parser::parse_one() { auto body = parse_body(); + LOG_DEBUG("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) }) ); } @@ -170,6 +172,7 @@ bool Parser::parse_one() } lex.check_consume(';'); + LOG_DEBUG("static " << p); tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(s) )); } else if( lex.consume_if("type") ) @@ -290,6 +293,7 @@ bool Parser::parse_one() throw "ERROR"; } + LOG_DEBUG("type " << p); auto it = this->tree.data_types.find(p); if( it != this->tree.data_types.end() ) { -- cgit v1.2.3 From d526acefc4a2ac90f56b9369615250ba293e959e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 17:10:20 +0800 Subject: Codegen MMIR - Fix main return type --- src/trans/codegen_mmir.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index dd6f1468..9755bb8b 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#(isize, *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() ) { @@ -1018,6 +1018,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 ++) { @@ -1025,6 +1031,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"; @@ -1033,7 +1040,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); -- cgit v1.2.3 From ee65f12f4aeb27238c8a2fc07fbe84eceafdde26 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 13 May 2018 21:29:27 +0800 Subject: Standalone MIRI - Refactor to remove linkage of host and VM stack --- tools/standalone_miri/main.cpp | 2400 +++++++++++++++++++++------------------- 1 file changed, 1268 insertions(+), 1132 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index bd86967c..1ab5b955 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -41,9 +41,58 @@ struct ThreadState }; unsigned ThreadState::s_next_tls_key = 1; -Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, ::std::vector args); -Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector args); -Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector args); +class InterpreterThread +{ + friend struct MirHelpers; + struct StackFrame + { + ::std::function cb; + const Function& fcn; + Value ret; + ::std::vector args; + ::std::vector locals; + ::std::vector drop_flags; + + unsigned bb_idx; + unsigned stmt_idx; + + StackFrame(const Function& fcn, ::std::vector args); + static StackFrame make_wrapper(::std::function cb) { + static Function f; + StackFrame rv(f, {}); + rv.cb = ::std::move(cb); + return rv; + } + }; + + ModuleTree& m_modtree; + ThreadState m_thread; + ::std::vector m_stack; + +public: + InterpreterThread(ModuleTree& modtree): + m_modtree(modtree) + { + } + ~InterpreterThread(); + + void start(const ::HIR::Path& p, ::std::vector 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 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 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 args); + + // Returns true if the call was resolved instantly + bool drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow=false); +}; int main(int argc, const char* argv[]) { @@ -63,16 +112,22 @@ int main(int argc, const char* argv[]) 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\0\0\0\0", 8); - val_argv.write_bytes(0, "\0\0\0\0\0\0\0", argv_ty.get_size()); + val_argc.write_isize(0, 0); + val_argv.write_usize(0, 0); try { - ThreadState ts; + InterpreterThread root_thread(tree); + ::std::vector args; args.push_back(::std::move(val_argc)); args.push_back(::std::move(val_argv)); - auto rv = MIRI_Invoke( tree, ts, tree.find_lang_item("start"), ::std::move(args) ); + Value rv; + root_thread.start(tree.find_lang_item("start"), ::std::move(args)); + while( !root_thread.step_one(rv) ) + { + } + ::std::cout << rv << ::std::endl; } catch(const DebugExceptionTodo& /*e*/) @@ -311,726 +366,573 @@ struct Ops { } }; -namespace +struct MirHelpers { + InterpreterThread& thread; + InterpreterThread::StackFrame& frame; - void drop_value(ModuleTree& modtree, ThreadState& thread, Value ptr, const ::HIR::TypeRef& ty, bool is_shallow=false) + MirHelpers(InterpreterThread& thread, InterpreterThread::StackFrame& frame): + thread(thread), + frame(frame) { - if( is_shallow ) - { - // HACK: Only works for Box 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 ; - } - if( ty.wrappers.empty() ) + } + + ValueRef get_value_and_type(const ::MIR::LValue& lv, ::HIR::TypeRef& ty) + { + switch(lv.tag()) { - if( ty.inner_type == RawType::Composite ) + 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); + if( array_ty.wrappers.empty() ) + LOG_ERROR("Indexing non-array/slice - " << array_ty); + if( array_ty.wrappers.front().type == TypeWrapper::Ty::Array ) { - if( ty.composite_type->drop_glue != ::HIR::Path() ) - { - LOG_DEBUG("Drop - " << ty); - - MIRI_Invoke(modtree, thread, ty.composite_type->drop_glue, { ptr }); - } - else - { - // No drop glue - } + ty = array_ty.get_inner(); + base_val.m_offset += ty.get_size() * idx; + return base_val; } - else if( ty.inner_type == RawType::TraitObject ) + else if( array_ty.wrappers.front().type == TypeWrapper::Ty::Slice ) { - LOG_TODO("Drop - " << ty << " - trait object"); + LOG_TODO("Slice index"); } else { - // No destructor + LOG_ERROR("Indexing non-array/slice - " << array_ty); + throw "ERROR"; } - } - else - { - switch( ty.wrappers[0].type ) + } 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) ) { - case TypeWrapper::Ty::Borrow: - if( ty.wrappers[0].size == static_cast(::HIR::BorrowType::Move) ) + 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& 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); + // 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 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( val.read_value(POINTER_SIZE, meta_size) ); + + // TODO: Get a more sane size from the metadata + if( alloc ) { - LOG_TODO("Drop - " << ty << " - dereference and go to inner"); - // TODO: Clear validity on the entire inner value. + LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs); + size = alloc.get_size() - ofs; } else { - // No destructor + size = 0; } - break; - case TypeWrapper::Ty::Pointer: - // No destructor - break; - // TODO: Arrays - default: - LOG_TODO("Drop - " << ty << " - array?"); - break; } + 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 ""; } - -} - -Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, ::std::vector args) -{ - Value ret; - - const auto& fcn = modtree.get_function(path); - - - // TODO: Support overriding certain functions + ValueRef get_value_ref(const ::MIR::LValue& lv) { - 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; - } - - // - 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 ret; - } - - // - No stack overflow handling needed - if( path == ::HIR::SimplePath { "std", { "sys", "imp", "stack_overflow", "imp", "init" } } ) - { - return ret; - } + ::HIR::TypeRef tmp; + return get_value_and_type(lv, tmp); } - if( fcn.external.link_name != "" ) + ::HIR::TypeRef get_lvalue_ty(const ::MIR::LValue& lv) { - // External function! - ret = MIRI_Invoke_Extern(modtree, thread, fcn.external.link_name, fcn.external.link_abi, ::std::move(args)); - LOG_DEBUG(path << " = " << ret); - return ret; + ::HIR::TypeRef ty; + get_value_and_type(lv, ty); + return ty; } - // Recursion limit. - if( thread.call_stack_depth > 40 ) { - LOG_ERROR("Recursion limit exceeded"); - } - auto _ = thread.enter_function(); + Value read_lvalue_with_ty(const ::MIR::LValue& lv, ::HIR::TypeRef& ty) + { + auto base_value = get_value_and_type(lv, ty); - TRACE_FUNCTION_R(path, path << " = " << ret); - for(size_t i = 0; i < args.size(); i ++) + return base_value.read_value(0, ty.get_size()); + } + Value read_lvalue(const ::MIR::LValue& lv) { - LOG_DEBUG("- Argument(" << i << ") = " << args[i]); - // TODO: Check argument sizes against prototype? + ::HIR::TypeRef ty; + return read_lvalue_with_ty(lv, ty); } - - ret = Value(fcn.ret_ty == RawType::Unreachable ? ::HIR::TypeRef() : fcn.ret_ty); - - struct State + void write_lvalue(const ::MIR::LValue& lv, Value val) { - ModuleTree& modtree; - const Function& fcn; - Value& ret; - ::std::vector args; - ::std::vector locals; - ::std::vector drop_flags; - - State(ModuleTree& modtree, const Function& fcn, Value& ret, ::std::vector 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) { - /*const*/ auto& s = modtree.get_static(e); - ty = s.ty; - return ValueRef(s.val, 0, s.val.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() == 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& 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); - // 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 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( val.read_value(POINTER_SIZE, meta_size) ); + //LOG_DEBUG(lv << " = " << val); + ::HIR::TypeRef ty; + auto base_value = get_value_and_type(lv, ty); - // TODO: Get a more sane size from the metadata - if( alloc ) - { - LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs); - size = alloc.get_size() - ofs; - } - else - { - size = 0; - } - } - 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); + if(base_value.m_alloc) { + base_value.m_alloc.alloc().write_value(base_value.m_offset, ::std::move(val)); } - - ::HIR::TypeRef get_lvalue_ty(const ::MIR::LValue& lv) - { - ::HIR::TypeRef ty; - get_value_and_type(lv, ty); - return ty; + else { + base_value.m_value->write_value(base_value.m_offset, ::std::move(val)); } + } - 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) + Value const_to_value(const ::MIR::Constant& c, ::HIR::TypeRef& ty) + { + switch(c.tag()) { - //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)); + 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(ce.v); + val.write_bytes(0, &v, ::std::min(ty.get_size(), sizeof(v))); // TODO: Endian/format? } else { - base_value.m_value->write_value(base_value.m_offset, ::std::move(val)); + throw ::std::runtime_error("BUG: Invalid type in Constant::Float"); } - } - - 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(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); + 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; + // --> 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; 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()); + val.allocation.alloc().relocations.push_back(Relocation { 0, s->val.allocation }); 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) ) { - ty = ::HIR::TypeRef(RawType::Function); - return Value::new_fnptr(ce); - } - if( const auto* s = modtree.get_static_opt(ce) ) { - ty = s->ty; - ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); - Value val = Value(ty); - val.write_usize(0, 0); - val.allocation.alloc().relocations.push_back(Relocation { 0, s->val.allocation }); - return val; - } - LOG_TODO("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 ""; + LOG_ERROR("Constant::ItemAddr - " << ce << " - not found"); + } break; } - Value param_to_value(const ::MIR::Param& p) + 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()) { - ::HIR::TypeRef ty; - return param_to_value(p, ty); + 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) + ValueRef get_value_ref_param(const ::MIR::Param& p, Value& tmp, ::HIR::TypeRef& ty) + { + switch(p.tag()) { - 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 ""; + 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); } - } state { modtree, fcn, ret, ::std::move(args) }; + throw ""; + } +}; - size_t bb_idx = 0; - for(;;) +// ==================================================================== +// +// ==================================================================== +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 << ": " << 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 args) +{ + Value v; + if( this->call_path(v, p, ::std::move(args)) ) { - const auto& bb = fcn.m_mir.blocks.at(bb_idx); + 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 ); - for(const auto& stmt : bb.statements) + 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()) { - 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::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 ) { - 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 = 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(re.type) }); - - new_val = Value(src_ty); - // ^ Pointer value - new_val.write_usize(0, ofs); - if( meta != RawType::Unreachable ) + if( !src_base_value.m_value->allocation ) { - 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); + src_base_value.m_value->create_allocation(); } - // - 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()); + 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(re.type) }); + + new_val = Value(src_ty); + // ^ Pointer value + new_val.write_usize(0, ofs); + 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); + } + // - 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"; } - else if( !re.type.wrappers.empty() ) + if( !src_ty.wrappers.empty() ) { - // Destination can only be a raw pointer - if( re.type.wrappers.at(0).type != TypeWrapper::Ty::Pointer ) { + // 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.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()); - } + 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 + 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() ) + else { - // 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"; + if( src_ty == RawType::Function ) + { } - // 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); + 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 + } + 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) { - // 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( 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( src_value.read_u8 (0) ); break; + case RawType::I8: dst_val = static_cast( src_value.read_i8 (0) ); break; + case RawType::U16: dst_val = static_cast( src_value.read_u16(0) ); break; + case RawType::I16: dst_val = static_cast( src_value.read_i16(0) ); break; + case RawType::U32: dst_val = static_cast( src_value.read_u32(0) ); break; + case RawType::I32: dst_val = static_cast( src_value.read_i32(0) ); break; + case RawType::U64: dst_val = static_cast( src_value.read_u64(0) ); break; + case RawType::I64: dst_val = static_cast( 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: + 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( src_value.read_f32(0) ); break; + case RawType::USize: dst_val = static_cast( src_value.read_usize(0) ); break; + case RawType::ISize: dst_val = static_cast( src_value.read_isize(0) ); break; + case RawType::U8: dst_val = static_cast( src_value.read_u8 (0) ); break; + case RawType::I8: dst_val = static_cast( src_value.read_i8 (0) ); break; + case RawType::U16: dst_val = static_cast( src_value.read_u16(0) ); break; + case RawType::I16: dst_val = static_cast( src_value.read_i16(0) ); break; + case RawType::U32: dst_val = static_cast( src_value.read_u32(0) ); break; + case RawType::I32: dst_val = static_cast( src_value.read_i32(0) ); break; + case RawType::U64: dst_val = static_cast( src_value.read_u64(0) ); break; + case RawType::I64: dst_val = static_cast( 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::Function: 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_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( 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( src_value.read_u8 (0) ); break; - case RawType::I8: dst_val = static_cast( src_value.read_i8 (0) ); break; - case RawType::U16: dst_val = static_cast( src_value.read_u16(0) ); break; - case RawType::I16: dst_val = static_cast( src_value.read_i16(0) ); break; - case RawType::U32: dst_val = static_cast( src_value.read_u32(0) ); break; - case RawType::I32: dst_val = static_cast( src_value.read_i32(0) ); break; - case RawType::U64: dst_val = static_cast( src_value.read_u64(0) ); break; - case RawType::I64: dst_val = static_cast( 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; + 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); } - 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( src_value.read_f32(0) ); break; - case RawType::USize: dst_val = static_cast( src_value.read_usize(0) ); break; - case RawType::ISize: dst_val = static_cast( src_value.read_isize(0) ); break; - case RawType::U8: dst_val = static_cast( src_value.read_u8 (0) ); break; - case RawType::I8: dst_val = static_cast( src_value.read_i8 (0) ); break; - case RawType::U16: dst_val = static_cast( src_value.read_u16(0) ); break; - case RawType::I16: dst_val = static_cast( src_value.read_i16(0) ); break; - case RawType::U32: dst_val = static_cast( src_value.read_u32(0) ); break; - case RawType::I32: dst_val = static_cast( src_value.read_i32(0) ); break; - case RawType::U64: dst_val = static_cast( src_value.read_u64(0) ); break; - case RawType::I64: dst_val = static_cast( 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; + // 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(), ""); } - 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) + ::HIR::TypeRef tag_ty = dt.fields[0].second; + LOG_ASSERT(tag_ty.wrappers.empty(), ""); + switch(tag_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( src_value.read_usize(0) ); - if(0) - case RawType::ISize: - dst_val = static_cast( src_value.read_isize(0) ); - if(0) - case RawType::U8: - dst_val = static_cast( src_value.read_u8 (0) ); - if(0) - case RawType::I8: - dst_val = static_cast( src_value.read_i8 (0) ); - if(0) - case RawType::U16: - dst_val = static_cast( src_value.read_u16(0) ); - if(0) - case RawType::I16: - dst_val = static_cast( src_value.read_i16(0) ); - if(0) - case RawType::U32: - dst_val = static_cast( src_value.read_u32(0) ); - if(0) - case RawType::I32: - dst_val = static_cast( src_value.read_i32(0) ); - if(0) - case RawType::U64: - dst_val = static_cast( src_value.read_u64(0) ); - if(0) - case RawType::I64: - dst_val = static_cast( 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( src_value.read_u8 (0) ); - if(0) - case RawType::F64: - dst_val = static_cast( src_value.read_f64(0) ); - if(0) - case RawType::F32: - dst_val = static_cast( src_value.read_f32(0) ); - if(0) case RawType::USize: dst_val = static_cast( src_value.read_usize(0) ); if(0) @@ -1060,457 +962,503 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: if(0) case RawType::I64: dst_val = static_cast( 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(dst_val)); - break; - case RawType::U16: - new_val.write_u16(0, static_cast(dst_val)); - break; - case RawType::U32: - new_val.write_u32(0, static_cast(dst_val)); - break; - case RawType::U64: - new_val.write_u64(0, dst_val); - break; - case RawType::ISize: - new_val.write_usize(0, static_cast(dst_val)); - break; - case RawType::I8: - new_val.write_i8(0, static_cast(dst_val)); - break; - case RawType::I16: - new_val.write_i16(0, static_cast(dst_val)); - break; - case RawType::I32: - new_val.write_i32(0, static_cast(dst_val)); - break; - case RawType::I64: - new_val.write_i64(0, static_cast(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); + LOG_FATAL("Bad tag type in cast - " << tag_ty); } - } - 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)); + } if(0) + case RawType::Bool: + dst_val = static_cast( src_value.read_u8 (0) ); + if(0) + case RawType::F64: + dst_val = static_cast( src_value.read_f64(0) ); + if(0) + case RawType::F32: + dst_val = static_cast( src_value.read_f32(0) ); + if(0) + case RawType::USize: + dst_val = static_cast( src_value.read_usize(0) ); + if(0) + case RawType::ISize: + dst_val = static_cast( src_value.read_isize(0) ); + if(0) + case RawType::U8: + dst_val = static_cast( src_value.read_u8 (0) ); + if(0) + case RawType::I8: + dst_val = static_cast( src_value.read_i8 (0) ); + if(0) + case RawType::U16: + dst_val = static_cast( src_value.read_u16(0) ); + if(0) + case RawType::I16: + dst_val = static_cast( src_value.read_i16(0) ); + if(0) + case RawType::U32: + dst_val = static_cast( src_value.read_u32(0) ); + if(0) + case RawType::I32: + dst_val = static_cast( src_value.read_i32(0) ); + if(0) + case RawType::U64: + dst_val = static_cast( src_value.read_u64(0) ); + if(0) + case RawType::I64: + dst_val = static_cast( src_value.read_i64(0) ); - // Compare fat metadata. - if( res == 0 && v_l.m_size > POINTER_SIZE ) + switch(re.type.inner_type) { - 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)); + case RawType::USize: + new_val.write_usize(0, dst_val); + break; + case RawType::U8: + new_val.write_u8(0, static_cast(dst_val)); + break; + case RawType::U16: + new_val.write_u16(0, static_cast(dst_val)); + break; + case RawType::U32: + new_val.write_u32(0, static_cast(dst_val)); + break; + case RawType::U64: + new_val.write_u64(0, dst_val); + break; + case RawType::ISize: + new_val.write_usize(0, static_cast(dst_val)); + break; + case RawType::I8: + new_val.write_i8(0, static_cast(dst_val)); + break; + case RawType::I16: + new_val.write_i16(0, static_cast(dst_val)); + break; + case RawType::I32: + new_val.write_i32(0, static_cast(dst_val)); + break; + case RawType::I64: + new_val.write_i64(0, static_cast(dst_val)); + break; + default: + throw ""; } - } - 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(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(shift), re.op)); break; - case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast(shift), re.op)); break; - case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast(shift), re.op)); break; - case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast(shift), re.op)); break; - case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast(shift), re.op)); break; - // TODO: Is signed allowed? - default: - LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); + 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 ::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) - { - // 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(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(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(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; + case RawType::U128: + case RawType::I128: + LOG_TODO("Cast to " << re.type); } - } 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) + } + } 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 ) { - 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; + 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_ERROR("UniOp::INV not valid on type " << ty); + LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); } - break; } - } break; - TU_ARM(se.src, DstMeta, re) { - auto ptr = state.get_value_ref(re.val); + else if( ty_l.wrappers.front().type == TypeWrapper::Ty::Pointer ) + { + // TODO: Technically only EQ/NE are valid. - ::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); + res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); - 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); + // 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(); - for(size_t i = 0; i < re.vals.size(); i++) + 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 { - auto fld_ofs = dst_ty.composite_type->fields.at(i).first; - new_val.write_value(fld_ofs, state.param_to_value(re.vals[i])); + LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); } - } 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) + bool res_bool; + switch(re.op) { - new_val.write_value(ofs, state.param_to_value(v)); - ofs += stride; + 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; - 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++) + 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(v); }; + switch(ty_r.inner_type) { - new_val.write_value(ofs, state.param_to_value(re.val)); - ofs += stride; + 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(shift), re.op)); break; + case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast(shift), re.op)); break; + case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast(shift), re.op)); break; + case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast(shift), re.op)); break; + case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast(shift), re.op)); break; + // TODO: Is signed allowed? + default: + LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); } } 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 ) + 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) + { + // 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(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(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(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) { - const auto& fld = data_ty.fields.at(re.index); + 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; - new_val.write_value(fld.first, state.param_to_value(re.val)); + default: + LOG_TODO("Unsupported binary operator?"); } - LOG_DEBUG("Variant " << new_val); - if( var.base_field != SIZE_MAX ) + 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) { - ::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()); + 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); } - else + break; + case ::MIR::eUniOp::NEG: + switch(ty.inner_type) { - // Union, no tag + 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); } - LOG_DEBUG("Variant " << new_val); - } break; - TU_ARM(se.src, Struct, re) { - const auto& data_ty = state.modtree.get_composite(re.path); + 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); - ::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"); + 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 = data_ty.fields.at(i).first; - new_val.write_value(fld_ofs, state.param_to_value(re.vals[i])); - } - } break; + 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])); } - 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) ) + 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) { - ::HIR::TypeRef ty; - auto v = state.get_value_and_type(se.slot, ty); + 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); + 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 = 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"); - // - Take a pointer to the inner - auto alloc = v.m_alloc; - if( !alloc ) + 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 || 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 ) { - if( !v.m_value->allocation ) - { - v.m_value->create_allocation(); - } - alloc = AllocationPtr(v.m_value->allocation); + v.m_value->create_allocation(); } - size_t ofs = v.m_offset; - assert(ty.get_meta_type() == RawType::Unreachable); + alloc = AllocationPtr(v.m_value->allocation); + } + size_t ofs = v.m_offset; + assert(ty.get_meta_type() == RawType::Unreachable); - auto ptr_ty = ty.wrap(TypeWrapper::Ty::Borrow, 2); + 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) }); + auto ptr_val = Value(ptr_ty); + ptr_val.write_usize(0, ofs); + ptr_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) }); - // TODO: Shallow drop - drop_value(modtree, thread, ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW); - // TODO: Clear validity on the entire inner value. - //alloc.mark_as_freed(); + 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 : 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; } + } 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; } - - LOG_DEBUG("=== BB" << bb_idx << "/TERM: " << bb.terminator); + + 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 ""; @@ -1521,16 +1469,16 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: TU_ARM(bb.terminator, Panic, _te) LOG_TODO("Terminator::Panic"); TU_ARM(bb.terminator, Goto, te) - bb_idx = te; - continue; + cur_frame.bb_idx = te; + break; TU_ARM(bb.terminator, Return, _te) - LOG_DEBUG("RETURN " << state.ret); - return state.ret; + 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, ""); - bb_idx = v ? te.bb0 : te.bb1; - } continue; + 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); @@ -1578,8 +1526,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: { LOG_FATAL("Terminator::Switch on " << ty << " didn't find a variant"); } - bb_idx = te.targets.at(found_target); - } continue; + 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) { @@ -1589,10 +1537,15 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: 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(); - state.write_lvalue(te.ret_val, MIRI_Invoke_Intrinsic(modtree, thread, fe.name, fe.params, ::std::move(sub_args))); + 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 { @@ -1618,25 +1571,140 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: } LOG_DEBUG("Call " << *fcn_p); - auto v = MIRI_Invoke(modtree, thread, *fcn_p, ::std::move(sub_args)); - LOG_DEBUG(te.ret_val << " = " << v << " (resume " << path << ")"); - state.write_lvalue(te.ret_val, ::std::move(v)); + 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) + if( this->m_stack.back().cb ) + { + if( !this->m_stack.back().cb(res_v, ::std::move(res_v)) ) + { + return false; } - bb_idx = te.ret_block; - } continue; + 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 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 args) +{ + // 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 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; } - throw ""; } - throw ""; + 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); } - -Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector args) +bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, const ::std::string& abi, ::std::vector args) { if( link_name == "__rust_allocate" ) { @@ -1645,11 +1713,11 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: 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 = 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" ) { @@ -1669,7 +1737,7 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: 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)); + rv = ::std::move(args.at(0)); } else if( link_name == "__rust_deallocate" ) { @@ -1684,7 +1752,7 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: auto& alloc = alloc_ptr.alloc(); alloc.mark_as_freed(); // Just let it drop. - return Value(); + rv = Value(); } else if( link_name == "__rust_maybe_catch_panic" ) { @@ -1696,12 +1764,23 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: ::std::vector sub_args; sub_args.push_back( ::std::move(arg) ); - // TODO: Catch the panic out of this. - MIRI_Invoke(modtree, thread, fcn_path, ::std::move(sub_args)); + this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)->bool{ + out_rv = Value(::HIR::TypeRef(RawType::U32)); + out_rv.write_u32(0, 0); + return true; + })); - auto rv = Value(::HIR::TypeRef(RawType::U32)); - rv.write_u32(0,0); - return rv; + // 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" ) { @@ -1716,9 +1795,8 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: else if( link_name == "AddVectoredExceptionHandler" ) { LOG_DEBUG("Call `AddVectoredExceptionHandler` - Ignoring and returning non-null"); - auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv = Value(::HIR::TypeRef(RawType::USize)); rv.write_usize(0, 1); - return rv; } else if( link_name == "GetModuleHandleW" ) { @@ -1733,17 +1811,16 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: LOG_DEBUG("GetModuleHandleW(NULL)"); } - auto rv = GetModuleHandleW(static_cast(arg0)); - if(rv) + auto ret = GetModuleHandleW(static_cast(arg0)); + if(ret) { - return Value::new_ffiptr(FFIPointer { "GetModuleHandleW", rv }); + rv = Value::new_ffiptr(FFIPointer { "GetModuleHandleW", ret }); } else { - auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv = Value(::HIR::TypeRef(RawType::USize)); rv.create_allocation(); rv.write_usize(0,0); - return rv; } } else if( link_name == "GetProcAddress" ) @@ -1760,18 +1837,17 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: // TODO: Sanity check that it's a valid c string within its allocation LOG_DEBUG("FFI GetProcAddress(" << handle << ", \"" << static_cast(symname) << "\")"); - auto rv = GetProcAddress(static_cast(handle), static_cast(symname)); + auto ret = GetProcAddress(static_cast(handle), static_cast(symname)); - if( rv ) + if( ret ) { - return Value::new_ffiptr(FFIPointer { "GetProcAddress", rv }); + rv = Value::new_ffiptr(FFIPointer { "GetProcAddress", ret }); } else { - auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv = Value(::HIR::TypeRef(RawType::USize)); rv.create_allocation(); rv.write_usize(0,0); - return rv; } } #else @@ -1784,48 +1860,43 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: ssize_t val = write(fd, buf, count); - auto rv = Value(::HIR::TypeRef(RawType::ISize)); + rv = Value(::HIR::TypeRef(RawType::ISize)); rv.write_isize(0, val); - return rv; } else if( link_name == "sysconf" ) { auto name = args.at(0).read_i32(0); LOG_DEBUG("FFI sysconf(" << name << ")"); + long val = sysconf(name); - auto rv = Value(::HIR::TypeRef(RawType::USize)); + + rv = Value(::HIR::TypeRef(RawType::USize)); rv.write_usize(0, val); - return rv; } else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" || link_name == "pthread_mutex_destroy" ) { - auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); - return rv; } else if( link_name == "pthread_rwlock_rdlock" ) { - auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); - return rv; } else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" ) { - auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); - return rv; } else if( link_name == "pthread_condattr_init" || link_name == "pthread_condattr_destroy" || link_name == "pthread_condattr_setclock" ) { - auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); - return rv; } else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) { - auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); - return rv; } else if( link_name == "pthread_key_create" ) { @@ -1834,20 +1905,18 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: auto key = ThreadState::s_next_tls_key ++; key_ref.m_alloc.alloc().write_u32( key_ref.m_offset, key ); - auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); - return rv; } 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 < thread.tls_values.size() ? thread.tls_values[key] : 0; + uint64_t v = key < m_thread.tls_values.size() ? m_thread.tls_values[key] : 0; - auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv = Value(::HIR::TypeRef(RawType::USize)); rv.write_usize(0, v); - return rv; } else if( link_name == "pthread_setspecific" ) { @@ -1855,29 +1924,26 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: auto v = args.at(1).read_u64(0); // Get a pointer-sized value from storage - if( key >= thread.tls_values.size() ) { - thread.tls_values.resize(key+1); + if( key >= m_thread.tls_values.size() ) { + m_thread.tls_values.resize(key+1); } - thread.tls_values[key] = v; + m_thread.tls_values[key] = v; - auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); - return rv; } else if( link_name == "pthread_key_delete" ) { - auto rv = Value(::HIR::TypeRef(RawType::I32)); + rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); - return rv; } #endif // std C else if( link_name == "signal" ) { LOG_DEBUG("Call `signal` - Ignoring and returning SIG_IGN"); - auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv = Value(::HIR::TypeRef(RawType::USize)); rv.write_usize(0, 1); - return rv; } // - `void *memchr(const void *s, int c, size_t n);` else if( link_name == "memchr" ) @@ -1890,7 +1956,7 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: const void* ret = memchr(ptr, c, n); - auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv = Value(::HIR::TypeRef(RawType::USize)); rv.create_allocation(); if( ret ) { @@ -1901,7 +1967,6 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: { rv.write_usize(0, 0); } - return rv; } else if( link_name == "memrchr" ) { @@ -1912,7 +1977,7 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: const void* ret = memrchr(ptr, c, n); - auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv = Value(::HIR::TypeRef(RawType::USize)); rv.create_allocation(); if( ret ) { @@ -1923,18 +1988,17 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: { rv.write_usize(0, 0); } - return rv; } // Allocators! else { LOG_TODO("Call external function " << link_name); } - throw ""; + return true; } -Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector args) + +bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector args) { - Value rv; TRACE_FUNCTION_R(name, rv); for(const auto& a : args) LOG_DEBUG("#" << (&a - args.data()) << ": " << a); @@ -1953,7 +2017,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st } else if( name == "atomic_fence" || name == "atomic_fence_acq" ) { - return Value(); + rv = Value(); } else if( name == "atomic_store" ) { @@ -1986,6 +2050,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st 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" ) @@ -2056,7 +2121,6 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st else { rv.write_u8( old_v.size(), 0 ); } - return rv; } else if( name == "transmute" ) { @@ -2180,13 +2244,17 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st auto ptr = val.read_value(0, POINTER_SIZE); for(size_t i = 0; i < item_count; i ++) { - drop_value(modtree, thread, ptr, ity); + // TODO: Nested calls? + if( !drop_value(ptr, ity) ) + { + LOG_DEBUG("Handle multiple queued calls"); + } ptr.write_usize(0, ptr.read_usize(0) + item_size); } } else { - drop_value(modtree, thread, val, ty); + return drop_value(val, ty); } } // ---------------------------------------------------------------- @@ -2203,7 +2271,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st ::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); + const auto& dty = m_modtree.get_composite(gp); rv = Value(::HIR::TypeRef(&dty)); lhs.get().write_to_value(rv, dty.fields[0].first); @@ -2221,7 +2289,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st ::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); + const auto& dty = m_modtree.get_composite(gp); rv = Value(::HIR::TypeRef(&dty)); lhs.get().write_to_value(rv, dty.fields[0].first); @@ -2239,7 +2307,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st ::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); + const auto& dty = m_modtree.get_composite(gp); rv = Value(::HIR::TypeRef(&dty)); lhs.get().write_to_value(rv, dty.fields[0].first); @@ -2298,7 +2366,75 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st { LOG_TODO("Call intrinsic \"" << name << "\""); } - return rv; + return true; +} + +bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow/*=false*/) +{ + if( is_shallow ) + { + // HACK: Only works for Box 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( ty.wrappers.empty() ) + { + 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 + } + } + else + { + switch( ty.wrappers[0].type ) + { + case TypeWrapper::Ty::Borrow: + if( ty.wrappers[0].size == static_cast(::HIR::BorrowType::Move) ) + { + LOG_TODO("Drop - " << ty << " - dereference and go to inner"); + // TODO: Clear validity on the entire inner value. + } + else + { + // No destructor + } + break; + case TypeWrapper::Ty::Pointer: + // No destructor + break; + // TODO: Arrays + default: + LOG_TODO("Drop - " << ty << " - array?"); + break; + } + } + return true; } int ProgramOptions::parse(int argc, const char* argv[]) -- cgit v1.2.3 From 55ea64451a81be2f797094c9a4140a7a98ba6b5d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 15 May 2018 21:25:47 +0800 Subject: Standalone MIRI - Split AllocationPtr into AllocationHandle and RelocationPtr --- tools/standalone_miri/main.cpp | 94 +++++++-------- tools/standalone_miri/module_tree.cpp | 6 +- tools/standalone_miri/value.cpp | 208 +++++++++++++++++++++------------- tools/standalone_miri/value.hpp | 190 +++++++++++++++++-------------- 4 files changed, 280 insertions(+), 218 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 1ab5b955..cd521501 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -153,7 +153,7 @@ public: 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(ValueCommon& tgt, size_t ofs) const = 0; + virtual void write_to_value(ValueCommonWrite& tgt, size_t ofs) const = 0; template const T& check(const char* opname) const @@ -212,14 +212,14 @@ struct PrimitiveUInt: struct PrimitiveU64: public PrimitiveUInt { PrimitiveU64(uint64_t v): PrimitiveUInt(v) {} - void write_to_value(ValueCommon& tgt, size_t ofs) const override { + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { tgt.write_u64(ofs, this->v); } }; struct PrimitiveU32: public PrimitiveUInt { PrimitiveU32(uint32_t v): PrimitiveUInt(v) {} - void write_to_value(ValueCommon& tgt, size_t ofs) const override { + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { tgt.write_u32(ofs, this->v); } }; @@ -273,14 +273,14 @@ struct PrimitiveSInt: struct PrimitiveI64: public PrimitiveSInt { PrimitiveI64(int64_t v): PrimitiveSInt(v) {} - void write_to_value(ValueCommon& tgt, size_t ofs) const override { + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { tgt.write_i64(ofs, this->v); } }; struct PrimitiveI32: public PrimitiveSInt { PrimitiveI32(int32_t v): PrimitiveSInt(v) {} - void write_to_value(ValueCommon& tgt, size_t ofs) const override { + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { tgt.write_i32(ofs, this->v); } }; @@ -458,11 +458,8 @@ struct MirHelpers 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); + 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() ) { @@ -595,7 +592,7 @@ struct MirHelpers 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) }); + val.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_string(&ce) }); LOG_DEBUG(c << " = " << val); //return Value::new_dataptr(ce.data()); return val; @@ -612,7 +609,7 @@ struct MirHelpers ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); Value val = Value(ty); val.write_usize(0, 0); - val.allocation.alloc().relocations.push_back(Relocation { 0, s->val.allocation }); + val.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_alloc(s->val.allocation) }); return val; } LOG_ERROR("Constant::ItemAddr - " << ce << " - not found"); @@ -676,6 +673,7 @@ InterpreterThread::~InterpreterThread() } void InterpreterThread::start(const ::HIR::Path& p, ::std::vector args) { + assert( this->m_stack.empty() ); Value v; if( this->call_path(v, p, ::std::move(args)) ) { @@ -720,7 +718,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) { src_base_value.m_value->create_allocation(); } - alloc = AllocationPtr(src_base_value.m_value->allocation); + alloc = RelocationPtr::new_alloc( src_base_value.m_value->allocation ); } if( alloc.is_alloc() ) LOG_DEBUG("- alloc=" << alloc << " (" << alloc.alloc() << ")"); @@ -740,7 +738,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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) }); + new_val.allocation->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? @@ -1073,8 +1071,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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(); + 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 ) { @@ -1109,8 +1107,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) // 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(); + reloc_l = v_l.get_relocation(POINTER_SIZE); + reloc_r = v_r.get_relocation(POINTER_SIZE); if( res == 0 && reloc_l != reloc_r ) { @@ -1427,7 +1425,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) { v.m_value->create_allocation(); } - alloc = AllocationPtr(v.m_value->allocation); + alloc = RelocationPtr::new_alloc( v.m_value->allocation ); } size_t ofs = v.m_offset; assert(ty.get_meta_type() == RawType::Unreachable); @@ -1436,7 +1434,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) auto ptr_val = Value(ptr_ty); ptr_val.write_usize(0, ofs); - ptr_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) }); + ptr_val.allocation->relocations.push_back(Relocation { 0, ::std::move(alloc) }); if( !drop_value(ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW) ) { @@ -1549,7 +1547,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) } else { - AllocationPtr fcn_alloc_ptr; + RelocationPtr fcn_alloc_ptr; const ::HIR::Path* fcn_p; if( te.fcn.is_Path() ) { fcn_p = &te.fcn.as_Path(); @@ -1561,12 +1559,10 @@ bool InterpreterThread::step_one(Value& out_thread_result) // TODO: Assert type // TODO: Assert offset/content. assert(v.read_usize(0) == 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)"); - fcn_alloc_ptr = alloc_ptr.alloc().get_relocation(v.m_offset); + 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() == AllocationPtr::Ty::Function, "Calling value that isn't a function pointer"); + LOG_ASSERT(fcn_alloc_ptr.get_ty() == RelocationPtr::Ty::Function, "Calling value that isn't a function pointer"); fcn_p = &fcn_alloc_ptr.fcn(); } @@ -1717,12 +1713,12 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c 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) }); + rv.allocation->relocations.push_back({ 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).allocation.alloc().get_relocation(0); + 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); @@ -1742,7 +1738,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c 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 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 << ")"); @@ -1948,8 +1944,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c // - `void *memchr(const void *s, int c, size_t n);` else if( link_name == "memchr" ) { - LOG_ASSERT(args.at(0).allocation.is_alloc(), ""); - auto ptr_alloc = args.at(0).allocation.alloc().get_relocation(0); + 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); @@ -1961,7 +1956,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c if( ret ) { rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast(ret) - static_cast(ptr) )); - rv.allocation.alloc().relocations.push_back({ 0, ptr_alloc }); + rv.allocation->relocations.push_back({ 0, ptr_alloc }); } else { @@ -1982,7 +1977,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c if( ret ) { rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast(ret) - static_cast(ptr) )); - rv.allocation.alloc().relocations.push_back({ 0, ptr_alloc }); + rv.allocation->relocations.push_back({ 0, ptr_alloc }); } else { @@ -2027,9 +2022,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con 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); + auto alloc = ptr_val.get_relocation(0); LOG_ASSERT(alloc, "Deref of a value with no relocation"); // TODO: Atomic side of this? @@ -2042,9 +2035,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con 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); + auto alloc = ptr_val.get_relocation(0); LOG_ASSERT(alloc, "Deref of a value with no relocation"); // TODO: Atomic lock the allocation. @@ -2057,7 +2048,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con { const auto& ty_T = ty_params.tys.at(0); auto ptr_ofs = args.at(0).read_usize(0); - auto ptr_alloc = args.at(0).allocation.alloc().get_relocation(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. @@ -2078,7 +2069,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con { const auto& ty_T = ty_params.tys.at(0); auto ptr_ofs = args.at(0).read_usize(0); - auto ptr_alloc = args.at(0).allocation.alloc().get_relocation(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. @@ -2146,7 +2137,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con rv = ::std::move(args.at(0)); rv.write_usize(0, new_ofs); if( ptr_alloc ) { - rv.allocation.alloc().relocations.push_back({ 0, ptr_alloc }); + rv.allocation->relocations.push_back({ 0, ptr_alloc }); } } // effectively ptr::write @@ -2160,12 +2151,13 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con // 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"); + + 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); - alloc.alloc().write_value(ofs, ::std::move(data_val)); - LOG_DEBUG(alloc.alloc()); + ptr_alloc.alloc().write_value(ofs, ::std::move(data_val)); + LOG_DEBUG(ptr_alloc.alloc()); } else if( name == "uninit" ) { @@ -2330,9 +2322,9 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con 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 src_alloc = args.at(0).get_relocation(0); auto dst_ofs = args.at(1).read_usize(0); - auto dst_alloc = args.at(1).allocation.alloc().get_relocation(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; @@ -2343,21 +2335,21 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con switch(src_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: { + 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 AllocationPtr::Ty::StdString: + 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 AllocationPtr::Ty::Function: + case RelocationPtr::Ty::Function: LOG_FATAL("Attempt to copy* a function"); break; - case AllocationPtr::Ty::FfiPointer: + case RelocationPtr::Ty::FfiPointer: LOG_BUG("Trying to copy from a FFI pointer"); break; } diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index ad41b33a..6a7a0b5f 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -151,13 +151,13 @@ bool Parser::parse_one() auto a = Allocation::new_alloc( reloc_str.size() ); //a.alloc().set_tag(); - a.alloc().write_bytes(0, reloc_str.data(), reloc_str.size()); - s.val.allocation.alloc().relocations.push_back({ ofs, ::std::move(a) }); + a->write_bytes(0, reloc_str.data(), reloc_str.size()); + s.val.allocation->relocations.push_back({ ofs, RelocationPtr::new_alloc(::std::move(a)) }); } else if( lex.next() == "::" || lex.next() == "<" ) { auto reloc_path = parse_path(); - s.val.allocation.alloc().relocations.push_back({ ofs, AllocationPtr::new_fcn(reloc_path) }); + s.val.allocation->relocations.push_back({ ofs, RelocationPtr::new_fcn(reloc_path) }); } else { diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index cdace6e2..d8eeee01 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -9,49 +9,79 @@ #include #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( reinterpret_cast(ptr) + static_cast(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( reinterpret_cast(ptr) + static_cast(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( reinterpret_cast(ptr) + static_cast(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( reinterpret_cast(ptr) + static_cast(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(x.get_ptr()) ); + *this = RelocationPtr::new_alloc(tmp); + tmp.m_ptr = nullptr; + } break; case Ty::Function: { auto ptr_i = reinterpret_cast(new ::HIR::Path(x.fcn())); assert( (ptr_i & 3) == 0 ); @@ -75,21 +105,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(get_ptr()) ); + break; case Ty::Function: { auto* ptr = const_cast<::HIR::Path*>(&fcn()); delete ptr; @@ -104,7 +128,7 @@ AllocationPtr::~AllocationPtr() } } } -size_t AllocationPtr::get_size() const +size_t RelocationPtr::get_size() const { if( !*this ) return 0; @@ -123,22 +147,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,17 +174,17 @@ size_t AllocationPtr::get_size() const return os; } -uint64_t ValueCommon::read_usize(size_t ofs) const +uint64_t ValueCommonRead::read_usize(size_t ofs) const { uint64_t v = 0; this->read_bytes(ofs, &v, POINTER_SIZE); return v; } -void ValueCommon::write_usize(size_t ofs, uint64_t v) +void ValueCommonWrite::write_usize(size_t ofs, uint64_t v) { this->write_bytes(ofs, &v, POINTER_SIZE); } -void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_size, bool& out_is_mut) const +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); @@ -180,7 +204,7 @@ void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& { switch(reloc.get_ty()) { - case AllocationPtr::Ty::Allocation: { + case RelocationPtr::Ty::Allocation: { auto& a = reloc.alloc(); if( ofs > a.size() ) LOG_FATAL("Out-of-bounds pointer"); @@ -191,7 +215,7 @@ void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_is_mut = true; return a.data_ptr() + ofs; } - case AllocationPtr::Ty::StdString: { + case RelocationPtr::Ty::StdString: { const auto& s = reloc.str(); if( ofs > s.size() ) LOG_FATAL("Out-of-bounds pointer"); @@ -201,9 +225,9 @@ void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_is_mut = false; return const_cast( static_cast(s.data() + ofs) ); } - case AllocationPtr::Ty::Function: + case RelocationPtr::Ty::Function: LOG_FATAL("read_pointer w/ function"); - case AllocationPtr::Ty::FfiPointer: + case RelocationPtr::Ty::FfiPointer: 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 @@ -214,7 +238,7 @@ void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& throw ""; } } -ValueRef ValueCommon::read_pointer_valref_mut(size_t rd_ofs, size_t size) +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); @@ -290,7 +314,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 }); } } @@ -303,7 +327,7 @@ Value Allocation::read_value(size_t ofs, size_t size) const bool v = (this->mask[j/8] & test_mask) != 0; if( v ) { - rv.allocation.alloc().mask[i/8] |= set_mask; + rv.allocation->mask[i/8] |= set_mask; } } } @@ -365,8 +389,8 @@ void Allocation::write_value(size_t ofs, Value v) // 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; @@ -575,18 +599,18 @@ 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; } @@ -595,10 +619,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 { @@ -606,7 +630,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 { @@ -635,7 +659,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 { @@ -652,7 +676,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 { @@ -670,7 +694,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 { @@ -698,7 +722,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 { @@ -719,14 +743,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 { @@ -749,7 +773,7 @@ void Value::write_value(size_t ofs, Value v) { if( v.allocation ) { - os << v.allocation.alloc(); + os << *v.allocation; } else { @@ -776,13 +800,13 @@ 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(); @@ -813,10 +837,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()); @@ -829,12 +853,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; @@ -855,6 +911,10 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) } os.setf(flags); } + else + { + // TODO: no value? + } return os; } @@ -868,9 +928,9 @@ Value ValueRef::read_value(size_t ofs, size_t size) const if( m_alloc ) { switch(m_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: + case RelocationPtr::Ty::Allocation: return m_alloc.alloc().read_value(m_offset + ofs, size); - case AllocationPtr::Ty::StdString: { + 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(), ""); @@ -893,9 +953,3 @@ bool ValueRef::compare(const void* other, size_t other_len) const check_bytes_valid(0, other_len); return ::std::memcmp(data_ptr(), other, other_len) == 0; } -uint64_t ValueRef::read_usize(size_t ofs) const -{ - uint64_t v = 0; - this->read_bytes(ofs, &v, POINTER_SIZE); - return v; -} diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index aa41b838..4da2eee6 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -23,12 +23,46 @@ struct FFIPointer void* ptr_value; }; -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, @@ -37,26 +71,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; @@ -98,7 +126,7 @@ public: return static_cast( reinterpret_cast(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( reinterpret_cast(m_ptr) & ~3 ); @@ -109,27 +137,14 @@ struct Relocation // Offset within parent allocation where this relocation is performed. // TODO: Size? size_t slot_ofs; - AllocationPtr backing_alloc; + RelocationPtr backing_alloc; }; -struct ValueCommon +// TODO: Split write and read +struct ValueCommonRead { - virtual AllocationPtr get_relocation(size_t ofs) const = 0; + virtual RelocationPtr get_relocation(size_t ofs) const = 0; virtual void read_bytes(size_t ofs, void* dst, size_t count) const = 0; - 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(v)); } - void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast(v)); } - void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast(v)); } - void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast(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(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; } @@ -164,16 +179,34 @@ struct ValueCommon /// Read a pointer and return a ValueRef to it (mutable data) ValueRef read_pointer_valref_mut(size_t rd_ofs, size_t size); }; +struct ValueCommonWrite: + public ValueCommonRead +{ + 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(v)); } + void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast(v)); } + void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast(v)); } + void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast(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(v)); } +}; class Allocation: - public ValueCommon + public ValueCommonWrite { - friend class AllocationPtr; + 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(this->data.data()); } uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->data.data()); } @@ -183,12 +216,12 @@ public: ::std::vector mask; ::std::vector relocations; - AllocationPtr get_relocation(size_t ofs) const override { + 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; @@ -211,10 +244,10 @@ public: extern ::std::ostream& operator<<(::std::ostream& os, const Allocation& x); struct Value: - public ValueCommon + 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 uint8_t mask[2]; @@ -228,15 +261,15 @@ struct Value: static Value new_ffiptr(FFIPointer ffi); void create_allocation(); - size_t size() const { return allocation ? allocation.alloc().size() : direct_data.size; } - const uint8_t* data_ptr() const { return allocation ? allocation.alloc().data_ptr() : direct_data.data; } - uint8_t* data_ptr() { return allocation ? allocation.alloc().data_ptr() : direct_data.data; } + 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; } - AllocationPtr get_relocation(size_t ofs) const override { - if( this->allocation && this->allocation.is_alloc() ) - return this->allocation.alloc().get_relocation(ofs); + RelocationPtr get_relocation(size_t ofs) const override { + if( this->allocation && this->allocation ) + return this->allocation->get_relocation(ofs); else - return AllocationPtr(); + return RelocationPtr(); } void check_bytes_valid(size_t ofs, size_t size) const; @@ -251,17 +284,17 @@ struct Value: 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 - //:public ValueCommon +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 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), @@ -271,12 +304,12 @@ struct ValueRef { switch(m_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: + 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 AllocationPtr::Ty::StdString: + case RelocationPtr::Ty::StdString: assert(ofs < m_alloc.str().size()); assert(size <= m_alloc.str().size()); assert(ofs+size <= m_alloc.str().size()); @@ -297,24 +330,21 @@ 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 && 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; @@ -322,10 +352,10 @@ struct ValueRef if( m_alloc ) { switch(m_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: + case RelocationPtr::Ty::Allocation: return m_alloc.alloc().data_ptr() + m_offset; break; - case AllocationPtr::Ty::StdString: + case RelocationPtr::Ty::StdString: return reinterpret_cast(m_alloc.str().data() + m_offset); default: throw "TODO"; @@ -347,10 +377,10 @@ struct ValueRef if( m_alloc ) { switch(m_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: + case RelocationPtr::Ty::Allocation: m_alloc.alloc().read_bytes(m_offset + ofs, dst, 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; @@ -372,10 +402,10 @@ struct ValueRef if( m_alloc ) { switch(m_alloc.get_ty()) { - case AllocationPtr::Ty::Allocation: + 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()); break; default: @@ -389,19 +419,5 @@ struct ValueRef } bool compare(const void* other, size_t other_len) const; - - // TODO: Figure out how to make this use `ValueCommon` when it can't write. - 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(read_u8(ofs)); } - int16_t read_i16(size_t ofs) const { return static_cast(read_u16(ofs)); } - int32_t read_i32(size_t ofs) const { return static_cast(read_u32(ofs)); } - int64_t read_i64(size_t ofs) const { return static_cast(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(read_usize(ofs)); } }; extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v); -- cgit v1.2.3 From c6f9ca14a3295c497b0f5ef6eec3b902fd8af3e7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 16 May 2018 21:35:16 +0800 Subject: Standalone MIRI - Split interpreter into its own file --- tools/standalone_miri/Makefile | 2 +- tools/standalone_miri/main.cpp | 2369 +--------------------------------------- tools/standalone_miri/miri.cpp | 2302 ++++++++++++++++++++++++++++++++++++++ tools/standalone_miri/miri.hpp | 79 ++ 4 files changed, 2387 insertions(+), 2365 deletions(-) create mode 100644 tools/standalone_miri/miri.cpp create mode 100644 tools/standalone_miri/miri.hpp diff --git a/tools/standalone_miri/Makefile b/tools/standalone_miri/Makefile index 95e99c75..f4dc0d0d 100644 --- a/tools/standalone_miri/Makefile +++ b/tools/standalone_miri/Makefile @@ -11,7 +11,7 @@ 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 +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 diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index cd521501..2011edfa 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -7,93 +7,19 @@ #include #include #include "debug.hpp" -#ifdef _WIN32 -# define NOMINMAX -# include -#endif +#include "miri.hpp" + struct ProgramOptions { ::std::string infile; + //TODO: Architecture file + //TODO: Loadable FFI descriptions + //TODO: Logfile int parse(int argc, const char* argv[]); }; -struct ThreadState -{ - static unsigned s_next_tls_key; - unsigned call_stack_depth; - ::std::vector 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 }; - } -}; -unsigned ThreadState::s_next_tls_key = 1; - -class InterpreterThread -{ - friend struct MirHelpers; - struct StackFrame - { - ::std::function cb; - const Function& fcn; - Value ret; - ::std::vector args; - ::std::vector locals; - ::std::vector drop_flags; - - unsigned bb_idx; - unsigned stmt_idx; - - StackFrame(const Function& fcn, ::std::vector args); - static StackFrame make_wrapper(::std::function cb) { - static Function f; - StackFrame rv(f, {}); - rv.cb = ::std::move(cb); - return rv; - } - }; - - ModuleTree& m_modtree; - ThreadState m_thread; - ::std::vector m_stack; - -public: - InterpreterThread(ModuleTree& modtree): - m_modtree(modtree) - { - } - ~InterpreterThread(); - - void start(const ::HIR::Path& p, ::std::vector 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 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 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 args); - - // Returns true if the call was resolved instantly - bool drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow=false); -}; - int main(int argc, const char* argv[]) { ProgramOptions opts; @@ -143,2291 +69,6 @@ int main(int argc, const char* argv[]) 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(ValueCommonWrite& tgt, size_t ofs) const = 0; - - template - const T& check(const char* opname) const - { - const auto* xp = dynamic_cast(this); - LOG_ASSERT(xp, "Attempting to " << opname << " mismatched types, expected " << typeid(T).name() << " got " << typeid(*this).name()); - return *xp; - } -}; -template -struct PrimitiveUInt: - public PrimitiveValue -{ - typedef PrimitiveUInt Self; - T v; - - PrimitiveUInt(T v): v(v) {} - ~PrimitiveUInt() override {} - - bool add(const PrimitiveValue& x) override { - const auto* xp = &x.check("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("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("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("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("modulo"); - if(xp->v == 0) return false; - T newv = this->v % xp->v; - this->v = newv; - return true; - } -}; -struct PrimitiveU64: public PrimitiveUInt -{ - 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 -{ - PrimitiveU32(uint32_t v): PrimitiveUInt(v) {} - void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { - tgt.write_u32(ofs, this->v); - } -}; -template -struct PrimitiveSInt: - public PrimitiveValue -{ - typedef PrimitiveSInt 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("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("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("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("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("modulo"); - if(xp->v == 0) return false; - T newv = this->v % xp->v; - this->v = newv; - return true; - } -}; -struct PrimitiveI64: public PrimitiveSInt -{ - 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 -{ - 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(&this->buf)->~PrimitiveValue(); - } - PrimitiveValue& get() { return *reinterpret_cast(&this->buf); } - const PrimitiveValue& get() const { return *reinterpret_cast(&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 - 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 - 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); - if( array_ty.wrappers.empty() ) - LOG_ERROR("Indexing non-array/slice - " << array_ty); - 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 ) - { - 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 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( val.read_value(POINTER_SIZE, meta_size) ); - - // TODO: Get a more sane size from the metadata - if( alloc ) - { - LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs); - size = alloc.get_size() - ofs; - } - else - { - size = 0; - } - } - 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) - { - //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(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->relocations.push_back(Relocation { 0, RelocationPtr::new_string(&ce) }); - LOG_DEBUG(c << " = " << val); - //return Value::new_dataptr(ce.data()); - 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; - ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); - Value val = Value(ty); - val.write_usize(0, 0); - val.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_alloc(s->val.allocation) }); - return val; - } - 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 << ": " << 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 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 ); - - 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(); - //bool is_slice_like = src_ty.has_slice_meta(); - src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast(re.type) }); - - new_val = Value(src_ty); - // ^ Pointer value - new_val.write_usize(0, ofs); - 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); - } - // - Add the relocation after writing the value (writing clears the relocations) - new_val.allocation->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: - 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( 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( src_value.read_u8 (0) ); break; - case RawType::I8: dst_val = static_cast( src_value.read_i8 (0) ); break; - case RawType::U16: dst_val = static_cast( src_value.read_u16(0) ); break; - case RawType::I16: dst_val = static_cast( src_value.read_i16(0) ); break; - case RawType::U32: dst_val = static_cast( src_value.read_u32(0) ); break; - case RawType::I32: dst_val = static_cast( src_value.read_i32(0) ); break; - case RawType::U64: dst_val = static_cast( src_value.read_u64(0) ); break; - case RawType::I64: dst_val = static_cast( 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( src_value.read_f32(0) ); break; - case RawType::USize: dst_val = static_cast( src_value.read_usize(0) ); break; - case RawType::ISize: dst_val = static_cast( src_value.read_isize(0) ); break; - case RawType::U8: dst_val = static_cast( src_value.read_u8 (0) ); break; - case RawType::I8: dst_val = static_cast( src_value.read_i8 (0) ); break; - case RawType::U16: dst_val = static_cast( src_value.read_u16(0) ); break; - case RawType::I16: dst_val = static_cast( src_value.read_i16(0) ); break; - case RawType::U32: dst_val = static_cast( src_value.read_u32(0) ); break; - case RawType::I32: dst_val = static_cast( src_value.read_i32(0) ); break; - case RawType::U64: dst_val = static_cast( src_value.read_u64(0) ); break; - case RawType::I64: dst_val = static_cast( 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( src_value.read_usize(0) ); - if(0) - case RawType::ISize: - dst_val = static_cast( src_value.read_isize(0) ); - if(0) - case RawType::U8: - dst_val = static_cast( src_value.read_u8 (0) ); - if(0) - case RawType::I8: - dst_val = static_cast( src_value.read_i8 (0) ); - if(0) - case RawType::U16: - dst_val = static_cast( src_value.read_u16(0) ); - if(0) - case RawType::I16: - dst_val = static_cast( src_value.read_i16(0) ); - if(0) - case RawType::U32: - dst_val = static_cast( src_value.read_u32(0) ); - if(0) - case RawType::I32: - dst_val = static_cast( src_value.read_i32(0) ); - if(0) - case RawType::U64: - dst_val = static_cast( src_value.read_u64(0) ); - if(0) - case RawType::I64: - dst_val = static_cast( 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( src_value.read_u8 (0) ); - if(0) - case RawType::F64: - dst_val = static_cast( src_value.read_f64(0) ); - if(0) - case RawType::F32: - dst_val = static_cast( src_value.read_f32(0) ); - if(0) - case RawType::USize: - dst_val = static_cast( src_value.read_usize(0) ); - if(0) - case RawType::ISize: - dst_val = static_cast( src_value.read_isize(0) ); - if(0) - case RawType::U8: - dst_val = static_cast( src_value.read_u8 (0) ); - if(0) - case RawType::I8: - dst_val = static_cast( src_value.read_i8 (0) ); - if(0) - case RawType::U16: - dst_val = static_cast( src_value.read_u16(0) ); - if(0) - case RawType::I16: - dst_val = static_cast( src_value.read_i16(0) ); - if(0) - case RawType::U32: - dst_val = static_cast( src_value.read_u32(0) ); - if(0) - case RawType::I32: - dst_val = static_cast( src_value.read_i32(0) ); - if(0) - case RawType::U64: - dst_val = static_cast( src_value.read_u64(0) ); - if(0) - case RawType::I64: - dst_val = static_cast( 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(dst_val)); - break; - case RawType::U16: - new_val.write_u16(0, static_cast(dst_val)); - break; - case RawType::U32: - new_val.write_u32(0, static_cast(dst_val)); - break; - case RawType::U64: - new_val.write_u64(0, dst_val); - break; - case RawType::ISize: - new_val.write_usize(0, static_cast(dst_val)); - break; - case RawType::I8: - new_val.write_i8(0, static_cast(dst_val)); - break; - case RawType::I16: - new_val.write_i16(0, static_cast(dst_val)); - break; - case RawType::I32: - new_val.write_i32(0, static_cast(dst_val)); - break; - case RawType::I64: - new_val.write_i64(0, static_cast(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( 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 = 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); - } - 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(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(shift), re.op)); break; - case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast(shift), re.op)); break; - case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast(shift), re.op)); break; - case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast(shift), re.op)); break; - case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast(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.wrappers.empty(), "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(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(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(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.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: - 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); - 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 = 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); - 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.wrap(TypeWrapper::Ty::Borrow, 2); - - auto ptr_val = Value(ptr_ty); - ptr_val.write_usize(0, ofs); - ptr_val.allocation->relocations.push_back(Relocation { 0, ::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.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 - " << 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 tmp( var.tag_data.size() ); - v.read_bytes(tag_ofs, const_cast(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 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) - 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 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 args) -{ - // 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 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 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 }); - - rv = Value(rty); - rv.write_usize(0, 0); - // TODO: Use the alignment when making an allocation? - rv.allocation->relocations.push_back({ 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 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(::HIR::TypeRef(RawType::U32)); - out_rv.write_u32(0, 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(::HIR::TypeRef(RawType::USize)); - rv.write_usize(0, 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(arg0)); - if(ret) - { - rv = Value::new_ffiptr(FFIPointer { "GetModuleHandleW", ret }); - } - 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(symname) << "\")"); - - auto ret = GetProcAddress(static_cast(handle), static_cast(symname)); - - if( ret ) - { - rv = Value::new_ffiptr(FFIPointer { "GetProcAddress", ret }); - } - 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(::HIR::TypeRef(RawType::ISize)); - rv.write_isize(0, 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(::HIR::TypeRef(RawType::USize)); - rv.write_usize(0, 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(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); - } - else if( link_name == "pthread_rwlock_rdlock" ) - { - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); - } - else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" ) - { - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); - } - else if( link_name == "pthread_condattr_init" || link_name == "pthread_condattr_destroy" || link_name == "pthread_condattr_setclock" ) - { - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); - } - else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) - { - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 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(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 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(::HIR::TypeRef(RawType::USize)); - rv.write_usize(0, 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(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); - } - else if( link_name == "pthread_key_delete" ) - { - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 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(ret) - static_cast(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(ret) - static_cast(ptr) )); - rv.allocation->relocations.push_back({ 0, ptr_alloc }); - } - else - { - rv.write_usize(0, 0); - } - } - // 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 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 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_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 - { - 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); - 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: - // TODO: Only &move has a destructor - 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 ++) - { - // TODO: Nested calls? - if( !drop_value(ptr, ity) ) - { - LOG_DEBUG("Handle multiple queued calls"); - } - ptr.write_usize(0, ptr.read_usize(0) + item_size); - } - } - else - { - 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_BUG("Trying to copy from a FFI pointer"); - break; - } - } - else - { - LOG_TODO("Call intrinsic \"" << name << "\""); - } - return true; -} - -bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow/*=false*/) -{ - if( is_shallow ) - { - // HACK: Only works for Box 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( ty.wrappers.empty() ) - { - 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 - } - } - else - { - switch( ty.wrappers[0].type ) - { - case TypeWrapper::Ty::Borrow: - if( ty.wrappers[0].size == static_cast(::HIR::BorrowType::Move) ) - { - LOG_TODO("Drop - " << ty << " - dereference and go to inner"); - // TODO: Clear validity on the entire inner value. - } - else - { - // No destructor - } - break; - case TypeWrapper::Ty::Pointer: - // No destructor - break; - // TODO: Arrays - default: - LOG_TODO("Drop - " << ty << " - array?"); - break; - } - } - return true; -} int ProgramOptions::parse(int argc, const char* argv[]) { diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp new file mode 100644 index 00000000..a4390e66 --- /dev/null +++ b/tools/standalone_miri/miri.cpp @@ -0,0 +1,2302 @@ +// +// +// +#include +#include "module_tree.hpp" +#include "value.hpp" +#include +#include +#include "debug.hpp" +#include "miri.hpp" +#ifdef _WIN32 +# define NOMINMAX +# include +#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 + const T& check(const char* opname) const + { + const auto* xp = dynamic_cast(this); + LOG_ASSERT(xp, "Attempting to " << opname << " mismatched types, expected " << typeid(T).name() << " got " << typeid(*this).name()); + return *xp; + } +}; +template +struct PrimitiveUInt: + public PrimitiveValue +{ + typedef PrimitiveUInt Self; + T v; + + PrimitiveUInt(T v): v(v) {} + ~PrimitiveUInt() override {} + + bool add(const PrimitiveValue& x) override { + const auto* xp = &x.check("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("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("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("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("modulo"); + if(xp->v == 0) return false; + T newv = this->v % xp->v; + this->v = newv; + return true; + } +}; +struct PrimitiveU64: public PrimitiveUInt +{ + 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 +{ + PrimitiveU32(uint32_t v): PrimitiveUInt(v) {} + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { + tgt.write_u32(ofs, this->v); + } +}; +template +struct PrimitiveSInt: + public PrimitiveValue +{ + typedef PrimitiveSInt 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("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("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("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("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("modulo"); + if(xp->v == 0) return false; + T newv = this->v % xp->v; + this->v = newv; + return true; + } +}; +struct PrimitiveI64: public PrimitiveSInt +{ + 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 +{ + 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(&this->buf)->~PrimitiveValue(); + } + PrimitiveValue& get() { return *reinterpret_cast(&this->buf); } + const PrimitiveValue& get() const { return *reinterpret_cast(&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 + 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 + 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); + if( array_ty.wrappers.empty() ) + LOG_ERROR("Indexing non-array/slice - " << array_ty); + 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 ) + { + 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 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( val.read_value(POINTER_SIZE, meta_size) ); + + // TODO: Get a more sane size from the metadata + if( alloc ) + { + LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs); + size = alloc.get_size() - ofs; + } + else + { + size = 0; + } + } + 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) + { + //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(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->relocations.push_back(Relocation { 0, RelocationPtr::new_string(&ce) }); + LOG_DEBUG(c << " = " << val); + //return Value::new_dataptr(ce.data()); + 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; + ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); + Value val = Value(ty); + val.write_usize(0, 0); + val.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_alloc(s->val.allocation) }); + return val; + } + 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 << ": " << 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 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 ); + + 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(); + //bool is_slice_like = src_ty.has_slice_meta(); + src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast(re.type) }); + + new_val = Value(src_ty); + // ^ Pointer value + new_val.write_usize(0, ofs); + 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); + } + // - Add the relocation after writing the value (writing clears the relocations) + new_val.allocation->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: + 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( 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( src_value.read_u8 (0) ); break; + case RawType::I8: dst_val = static_cast( src_value.read_i8 (0) ); break; + case RawType::U16: dst_val = static_cast( src_value.read_u16(0) ); break; + case RawType::I16: dst_val = static_cast( src_value.read_i16(0) ); break; + case RawType::U32: dst_val = static_cast( src_value.read_u32(0) ); break; + case RawType::I32: dst_val = static_cast( src_value.read_i32(0) ); break; + case RawType::U64: dst_val = static_cast( src_value.read_u64(0) ); break; + case RawType::I64: dst_val = static_cast( 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( src_value.read_f32(0) ); break; + case RawType::USize: dst_val = static_cast( src_value.read_usize(0) ); break; + case RawType::ISize: dst_val = static_cast( src_value.read_isize(0) ); break; + case RawType::U8: dst_val = static_cast( src_value.read_u8 (0) ); break; + case RawType::I8: dst_val = static_cast( src_value.read_i8 (0) ); break; + case RawType::U16: dst_val = static_cast( src_value.read_u16(0) ); break; + case RawType::I16: dst_val = static_cast( src_value.read_i16(0) ); break; + case RawType::U32: dst_val = static_cast( src_value.read_u32(0) ); break; + case RawType::I32: dst_val = static_cast( src_value.read_i32(0) ); break; + case RawType::U64: dst_val = static_cast( src_value.read_u64(0) ); break; + case RawType::I64: dst_val = static_cast( 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( src_value.read_usize(0) ); + if(0) + case RawType::ISize: + dst_val = static_cast( src_value.read_isize(0) ); + if(0) + case RawType::U8: + dst_val = static_cast( src_value.read_u8 (0) ); + if(0) + case RawType::I8: + dst_val = static_cast( src_value.read_i8 (0) ); + if(0) + case RawType::U16: + dst_val = static_cast( src_value.read_u16(0) ); + if(0) + case RawType::I16: + dst_val = static_cast( src_value.read_i16(0) ); + if(0) + case RawType::U32: + dst_val = static_cast( src_value.read_u32(0) ); + if(0) + case RawType::I32: + dst_val = static_cast( src_value.read_i32(0) ); + if(0) + case RawType::U64: + dst_val = static_cast( src_value.read_u64(0) ); + if(0) + case RawType::I64: + dst_val = static_cast( 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( src_value.read_u8 (0) ); + if(0) + case RawType::F64: + dst_val = static_cast( src_value.read_f64(0) ); + if(0) + case RawType::F32: + dst_val = static_cast( src_value.read_f32(0) ); + if(0) + case RawType::USize: + dst_val = static_cast( src_value.read_usize(0) ); + if(0) + case RawType::ISize: + dst_val = static_cast( src_value.read_isize(0) ); + if(0) + case RawType::U8: + dst_val = static_cast( src_value.read_u8 (0) ); + if(0) + case RawType::I8: + dst_val = static_cast( src_value.read_i8 (0) ); + if(0) + case RawType::U16: + dst_val = static_cast( src_value.read_u16(0) ); + if(0) + case RawType::I16: + dst_val = static_cast( src_value.read_i16(0) ); + if(0) + case RawType::U32: + dst_val = static_cast( src_value.read_u32(0) ); + if(0) + case RawType::I32: + dst_val = static_cast( src_value.read_i32(0) ); + if(0) + case RawType::U64: + dst_val = static_cast( src_value.read_u64(0) ); + if(0) + case RawType::I64: + dst_val = static_cast( 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(dst_val)); + break; + case RawType::U16: + new_val.write_u16(0, static_cast(dst_val)); + break; + case RawType::U32: + new_val.write_u32(0, static_cast(dst_val)); + break; + case RawType::U64: + new_val.write_u64(0, dst_val); + break; + case RawType::ISize: + new_val.write_usize(0, static_cast(dst_val)); + break; + case RawType::I8: + new_val.write_i8(0, static_cast(dst_val)); + break; + case RawType::I16: + new_val.write_i16(0, static_cast(dst_val)); + break; + case RawType::I32: + new_val.write_i32(0, static_cast(dst_val)); + break; + case RawType::I64: + new_val.write_i64(0, static_cast(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( 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 = 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); + } + 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(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(shift), re.op)); break; + case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast(shift), re.op)); break; + case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast(shift), re.op)); break; + case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast(shift), re.op)); break; + case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast(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.wrappers.empty(), "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(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(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(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.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: + 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); + 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 = 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); + 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.wrap(TypeWrapper::Ty::Borrow, 2); + + auto ptr_val = Value(ptr_ty); + ptr_val.write_usize(0, ofs); + ptr_val.allocation->relocations.push_back(Relocation { 0, ::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.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 - " << 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 tmp( var.tag_data.size() ); + v.read_bytes(tag_ofs, const_cast(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 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) + 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 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 args) +{ + // 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 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 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 }); + + rv = Value(rty); + rv.write_usize(0, 0); + // TODO: Use the alignment when making an allocation? + rv.allocation->relocations.push_back({ 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 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(::HIR::TypeRef(RawType::U32)); + out_rv.write_u32(0, 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(::HIR::TypeRef(RawType::USize)); + rv.write_usize(0, 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(arg0)); + if(ret) + { + rv = Value::new_ffiptr(FFIPointer { "GetModuleHandleW", ret }); + } + 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(symname) << "\")"); + + auto ret = GetProcAddress(static_cast(handle), static_cast(symname)); + + if( ret ) + { + rv = Value::new_ffiptr(FFIPointer { "GetProcAddress", ret }); + } + 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(::HIR::TypeRef(RawType::ISize)); + rv.write_isize(0, 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(::HIR::TypeRef(RawType::USize)); + rv.write_usize(0, 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(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + } + else if( link_name == "pthread_rwlock_rdlock" ) + { + rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + } + else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" ) + { + rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + } + else if( link_name == "pthread_condattr_init" || link_name == "pthread_condattr_destroy" || link_name == "pthread_condattr_setclock" ) + { + rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + } + else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) + { + rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 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(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 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(::HIR::TypeRef(RawType::USize)); + rv.write_usize(0, 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(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 0); + } + else if( link_name == "pthread_key_delete" ) + { + rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, 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(ret) - static_cast(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(ret) - static_cast(ptr) )); + rv.allocation->relocations.push_back({ 0, ptr_alloc }); + } + else + { + rv.write_usize(0, 0); + } + } + // 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 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 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_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 + { + 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); + 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: + // TODO: Only &move has a destructor + 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 ++) + { + // TODO: Nested calls? + if( !drop_value(ptr, ity) ) + { + LOG_DEBUG("Handle multiple queued calls"); + } + ptr.write_usize(0, ptr.read_usize(0) + item_size); + } + } + else + { + 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_BUG("Trying to copy from a FFI pointer"); + break; + } + } + else + { + LOG_TODO("Call intrinsic \"" << name << "\""); + } + return true; +} + +bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow/*=false*/) +{ + if( is_shallow ) + { + // HACK: Only works for Box 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( ty.wrappers.empty() ) + { + 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 + } + } + else + { + switch( ty.wrappers[0].type ) + { + case TypeWrapper::Ty::Borrow: + if( ty.wrappers[0].size == static_cast(::HIR::BorrowType::Move) ) + { + LOG_TODO("Drop - " << ty << " - dereference and go to inner"); + // TODO: Clear validity on the entire inner value. + } + else + { + // No destructor + } + break; + case TypeWrapper::Ty::Pointer: + // No destructor + break; + // TODO: Arrays + default: + LOG_TODO("Drop - " << ty << " - array?"); + break; + } + } + 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 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 cb; + const Function& fcn; + Value ret; + ::std::vector args; + ::std::vector locals; + ::std::vector drop_flags; + + unsigned bb_idx; + unsigned stmt_idx; + + StackFrame(const Function& fcn, ::std::vector args); + static StackFrame make_wrapper(::std::function cb) { + static Function f; + StackFrame rv(f, {}); + rv.cb = ::std::move(cb); + return rv; + } + }; + + ModuleTree& m_modtree; + ThreadState m_thread; + ::std::vector m_stack; + +public: + InterpreterThread(ModuleTree& modtree): + m_modtree(modtree) + { + } + ~InterpreterThread(); + + void start(const ::HIR::Path& p, ::std::vector 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 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 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 args); + + // Returns true if the call was resolved instantly + bool drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow=false); +}; + -- cgit v1.2.3 From 1320ff65f1fcce3cbd492eaf6f300ac81e2f8ae3 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 18 May 2018 19:37:01 +0800 Subject: Standalone MIRI - Range limit on FFI pointers --- tools/standalone_miri/miri.cpp | 4 ++-- tools/standalone_miri/value.hpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index a4390e66..f7e47a6b 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1682,7 +1682,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c auto ret = GetModuleHandleW(static_cast(arg0)); if(ret) { - rv = Value::new_ffiptr(FFIPointer { "GetModuleHandleW", ret }); + rv = Value::new_ffiptr(FFIPointer { "GetModuleHandleW", ret, 0 }); } else { @@ -1709,7 +1709,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c if( ret ) { - rv = Value::new_ffiptr(FFIPointer { "GetProcAddress", ret }); + rv = Value::new_ffiptr(FFIPointer { "GetProcAddress", ret, 0 }); } else { diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 4da2eee6..7219f1f7 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -21,6 +21,7 @@ struct FFIPointer { const char* source_function; void* ptr_value; + size_t size; }; class AllocationHandle -- cgit v1.2.3 From aada4f2fe9be2f9bfadb4ef6ba057f36b9860aa8 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 May 2018 08:09:14 +0800 Subject: Standalone MIRI - Pass argv to the target --- tools/standalone_miri/main.cpp | 46 +++++++++++++++++++++++++++++++++++++++-- tools/standalone_miri/miri.cpp | 23 ++++++++++++++++++++- tools/standalone_miri/value.cpp | 13 +++++++----- tools/standalone_miri/value.hpp | 5 +++++ 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 2011edfa..1755a9d7 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -14,10 +14,15 @@ struct ProgramOptions { ::std::string infile; //TODO: Architecture file + //::std::string archname; //TODO: Loadable FFI descriptions + //::std::vector ffi_api_files; //TODO: Logfile + //::std::string logfile; + ::std::vector args; int parse(int argc, const char* argv[]); + void show_help(const char* prog) const; }; int main(int argc, const char* argv[]) @@ -38,8 +43,19 @@ int main(int argc, const char* argv[]) 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_isize(0, 0); + + // Create argc/argv based on input arguments + val_argc.write_isize(0, 1 + opts.args.size()); + 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 ++) + { + 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 }) }); + } val_argv.write_usize(0, 0); + val_argv.allocation->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_alloc(argv_alloc) }); try { @@ -85,16 +101,37 @@ int ProgramOptions::parse(int argc, const char* argv[]) } else { - // TODO: Too many free arguments + this->args.push_back(arg); } } else if( arg[1] != '-' ) { // Short + if( arg[2] != '\0' ) { + // Error? + } + switch(arg[1]) + { + case 'h': + this->show_help(argv[0]); + exit(0); + default: + // TODO: Error + break; + } } else if( arg[2] != '\0' ) { // Long + if( ::std::strcmp(arg, "--help") == 0 ) { + this->show_help(argv[0]); + exit(0); + } + //else if( ::std::strcmp(arg, "--api") == 0 ) { + //} + else { + // TODO: Error + } } else { @@ -103,3 +140,8 @@ int ProgramOptions::parse(int argc, const char* argv[]) } return 0; } + +void ProgramOptions::show_help(const char* prog) const +{ + ::std::cout << "USAGE: " << prog << " <... args>" << ::std::endl; +} diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index f7e47a6b..eccc54c9 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1856,6 +1856,24 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c 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( 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 { @@ -2222,7 +2240,10 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con LOG_FATAL("Attempt to copy* a function"); break; case RelocationPtr::Ty::FfiPointer: - LOG_BUG("Trying to copy from a FFI pointer"); + 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; } } diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index d8eeee01..e9376ce6 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -227,13 +227,16 @@ void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size } case RelocationPtr::Ty::Function: LOG_FATAL("read_pointer w/ function"); - case RelocationPtr::Ty::FfiPointer: - if( req_valid ) - LOG_FATAL("Can't request valid data from a FFI pointer"); + 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 = 0; + out_size = f.size - ofs; out_is_mut = false; - return reloc.ffi().ptr_value /* + ofs */; + return reloc.ffi().ptr_value + ofs; + } } throw ""; } diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 7219f1f7..4528b98f 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -315,6 +315,11 @@ struct ValueRef: 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"; } -- cgit v1.2.3 From ae177706bf0b4b2ff05e9102d1403c73799756b0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 May 2018 10:15:20 +0800 Subject: Standalone MIRI - Better logging (can redirect to a file, leaving stdout for the program) --- test_smiri.sh | 2 +- tools/standalone_miri/debug.cpp | 34 +++++++++---- tools/standalone_miri/debug.hpp | 14 +++-- tools/standalone_miri/main.cpp | 61 +++++++++++++++++----- tools/standalone_miri/miri.cpp | 10 ++-- tools/standalone_miri/module_tree.cpp | 96 ++++++++++++++--------------------- tools/standalone_miri/value.cpp | 10 ++-- tools/standalone_miri/value.hpp | 15 ++++-- 8 files changed, 148 insertions(+), 94 deletions(-) diff --git a/test_smiri.sh b/test_smiri.sh index 63c94fa2..5a7de4e4 100755 --- a/test_smiri.sh +++ b/test_smiri.sh @@ -3,4 +3,4 @@ set -e cd $(dirname $0) make -f minicargo.mk MMIR=1 LIBS ./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 -./tools/bin/standalone_miri output-mmir/hello.mir +./tools/bin/standalone_miri output-mmir/hello.mir --logfile smiri_hello.log diff --git a/tools/standalone_miri/debug.cpp b/tools/standalone_miri/debug.cpp index 415bc5d5..f0476df7 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 unsigned DebugSink::s_indent = 0; +::std::unique_ptr DebugSink::s_out_file; DebugSink::DebugSink(::std::ostream& inner): m_inner(inner) @@ -10,39 +19,44 @@ DebugSink::~DebugSink() { m_inner << "\n"; } +bool DebugSink::set_output_file(const ::std::string& s) +{ + s_out_file.reset(new ::std::ofstream(s)); +} bool DebugSink::enabled(const char* fcn_name) { return true; } 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 +65,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 f7d32fe5..6b136ccb 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 #include +#include enum class DebugLevel { Trace, @@ -19,6 +24,7 @@ enum class DebugLevel { class DebugSink { static unsigned s_indent; + static ::std::unique_ptr s_out_file; ::std::ostream& m_inner; DebugSink(::std::ostream& inner); public: @@ -27,6 +33,7 @@ public: template ::std::ostream& operator<<(const T& v) { return m_inner << v; } + static bool 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. @@ -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/main.cpp b/tools/standalone_miri/main.cpp index 1755a9d7..c214676a 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -1,6 +1,10 @@ -// -// -// +/* + * mrustc Standalone MIRI + * - by John Hodge (Mutabah) + * + * main.cpp + * - Program entrypoint + */ #include #include "module_tree.hpp" #include "value.hpp" @@ -17,8 +21,10 @@ struct ProgramOptions //::std::string archname; //TODO: Loadable FFI descriptions //::std::vector ffi_api_files; - //TODO: Logfile - //::std::string logfile; + + // Output logfile + ::std::string logfile; + // Arguments for the program ::std::vector args; int parse(int argc, const char* argv[]); @@ -34,10 +40,17 @@ int main(int argc, const char* argv[]) return 1; } - auto tree = ModuleTree {}; + // Configure logging + if( opts.logfile != "" ) + { + DebugSink::set_output_file(opts.logfile); + } + // Load HIR tree + auto tree = ModuleTree {}; tree.load_file(opts.infile); + // Construct argc/argv values auto val_argc = Value( ::HIR::TypeRef{RawType::ISize} ); ::HIR::TypeRef argv_ty { RawType::I8 }; argv_ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, 0 }); @@ -54,9 +67,11 @@ int main(int argc, const char* argv[]) 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 }) }); } + //val_argv.write_ptr(0, 0, RelocationPtr::new_alloc(argv_alloc)); val_argv.write_usize(0, 0); val_argv.allocation->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_alloc(argv_alloc) }); + // Catch various exceptions from the interpreter try { InterpreterThread root_thread(tree); @@ -70,16 +85,24 @@ int main(int argc, const char* argv[]) { } - ::std::cout << rv << ::std::endl; + LOG_NOTICE("Return code: " << rv); } 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; + if(opts.logfile != "") + { + ::std::cerr << "- See '" << opts.logfile << "' for details" << ::std::endl; + } return 1; } @@ -89,26 +112,31 @@ int main(int argc, const char* argv[]) 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 { + // 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]) { @@ -116,8 +144,8 @@ int ProgramOptions::parse(int argc, const char* argv[]) this->show_help(argv[0]); exit(0); default: - // TODO: Error - break; + ::std::cerr << "Unexpected option -" << arg[1] << ::std::endl; + return 1; } } else if( arg[2] != '\0' ) @@ -127,10 +155,19 @@ int ProgramOptions::parse(int argc, const char* argv[]) 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 { - // TODO: Error + ::std::cerr << "Unexpected option " << arg << ::std::endl; + return 1; } } else diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index eccc54c9..733aa8a3 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1,6 +1,10 @@ -// -// -// +/* + * mrustc Standalone MIRI + * - by John Hodge (Mutabah) + * + * miri.cpp + * - Interpreter core + */ #include #include "module_tree.hpp" #include "value.hpp" diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 6a7a0b5f..cb6f943d 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -40,12 +40,11 @@ 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()) @@ -56,7 +55,7 @@ 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; + //TRACE_FUNCTION_F(""); if( lex.next() == "" ) // EOF? { return false; @@ -68,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(';'); @@ -78,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; @@ -94,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); @@ -102,7 +101,7 @@ bool Parser::parse_one() auto abi = ::std::move(lex.check_consume(TokenClass::String).strval); lex.check_consume(';'); - LOG_DEBUG("fn " << p); + 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}, {} }) ); } @@ -110,7 +109,7 @@ bool Parser::parse_one() { auto body = parse_body(); - LOG_DEBUG("fn " << p); + 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) }) ); } @@ -118,7 +117,7 @@ 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? @@ -152,12 +151,12 @@ bool Parser::parse_one() 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, RelocationPtr::new_alloc(::std::move(a)) }); + s.val.allocation->relocations.push_back({ ofs, /*size,*/ RelocationPtr::new_alloc(::std::move(a)) }); } else if( lex.next() == "::" || lex.next() == "<" ) { auto reloc_path = parse_path(); - s.val.allocation->relocations.push_back({ ofs, RelocationPtr::new_fcn(reloc_path) }); + s.val.allocation->relocations.push_back({ ofs, /*size,*/ RelocationPtr::new_fcn(reloc_path) }); } else { @@ -172,13 +171,13 @@ bool Parser::parse_one() } lex.check_consume(';'); - LOG_DEBUG("static " << p); + 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; @@ -223,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))); } @@ -289,11 +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("type " << p); + LOG_DEBUG(lex << "type " << p); auto it = this->tree.data_types.find(p); if( it != this->tree.data_types.end() ) { @@ -303,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 @@ -316,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"; @@ -360,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 @@ -372,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(it - var_names.begin())); } @@ -384,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(;;) { @@ -455,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") ) { @@ -471,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()); } } @@ -653,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); @@ -701,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); @@ -723,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) })); @@ -735,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( df_it - drop_flag_names.begin() ); lex.check_consume('='); @@ -754,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( df_it - drop_flag_names.begin() ); @@ -777,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( df_it - drop_flag_names.begin() ); } @@ -842,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); @@ -928,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('='); @@ -976,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('}'); @@ -1068,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. @@ -1124,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() @@ -1285,8 +1266,7 @@ 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) @@ -1312,8 +1292,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; } @@ -1331,8 +1310,7 @@ 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; } diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index e9376ce6..c3db284a 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" diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 4528b98f..81302e67 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -1,6 +1,10 @@ -// -// -// +/* + * mrustc Standalone MIRI + * - by John Hodge (Mutabah) + * + * value.hpp + * - Runtime values + */ #pragma once #include @@ -257,9 +261,12 @@ struct Value: 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_usize(uint64_t v); + //static Value new_isize(int64_t v); void create_allocation(); size_t size() const { return allocation ? allocation->size() : direct_data.size; } @@ -281,6 +288,8 @@ struct Value: void write_value(size_t ofs, Value v); 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); }; extern ::std::ostream& operator<<(::std::ostream& os, const Value& v); -- cgit v1.2.3 From a96b446e80f109138e2a639ec94222017af0b9b1 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 May 2018 12:29:44 +0800 Subject: Standalone MIRI - Use some more helpers --- test_smiri.sh | 4 +- tools/standalone_miri/hir_sim.cpp | 14 +++-- tools/standalone_miri/hir_sim.hpp | 7 ++- tools/standalone_miri/main.cpp | 18 +++---- tools/standalone_miri/miri.cpp | 104 +++++++++++++++----------------------- tools/standalone_miri/value.cpp | 41 +++++++++++++++ tools/standalone_miri/value.hpp | 14 +++-- 7 files changed, 117 insertions(+), 85 deletions(-) diff --git a/test_smiri.sh b/test_smiri.sh index 5a7de4e4..0dbad3fa 100755 --- a/test_smiri.sh +++ b/test_smiri.sh @@ -2,5 +2,7 @@ set -e cd $(dirname $0) make -f minicargo.mk MMIR=1 LIBS +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 -./tools/bin/standalone_miri output-mmir/hello.mir --logfile smiri_hello.log +echo "--- standalone_miri output-mmir/hello.mir" +time ./tools/bin/standalone_miri output-mmir/hello.mir --logfile smiri_hello.log diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index f3b4d400..94f0d0e1 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -20,6 +20,7 @@ size_t HIR::TypeRef::get_size(size_t ofs) const 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,7 +54,7 @@ size_t HIR::TypeRef::get_size(size_t ofs) const } throw ""; } - + switch(this->wrappers[ofs].type) { case TypeWrapper::Ty::Array: @@ -100,22 +101,25 @@ size_t HIR::TypeRef::get_size(size_t ofs) const } 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(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 { + out_inner_size = this->get_size(1); return (this->wrappers[0].type == TypeWrapper::Ty::Slice); } } @@ -130,9 +134,9 @@ HIR::TypeRef HIR::TypeRef::get_inner() const 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; } diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp index 1dc9bcc4..9f5ba59c 100644 --- a/tools/standalone_miri/hir_sim.hpp +++ b/tools/standalone_miri/hir_sim.hpp @@ -118,11 +118,14 @@ namespace HIR { } size_t get_size(size_t ofs=0) const; - bool has_slice_meta() const; // The attached metadata is a count + bool has_slice_meta(size_t& out_inner_size) const; // The attached metadata is a count of elements const TypeRef* get_usized_type(size_t& running_inner_size) const; TypeRef get_meta_type() const; TypeRef get_inner() const; - TypeRef wrap(TypeWrapper::Ty ty, size_t size) const; + TypeRef wrap(TypeWrapper::Ty ty, size_t size)&&; + TypeRef wrapped(TypeWrapper::Ty ty, size_t size) const { + return TypeRef(*this).wrap(ty, size); + } TypeRef get_field(size_t idx, size_t& ofs) const; bool operator==(const RawType& x) const { diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index c214676a..e3a8d22e 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -50,15 +50,7 @@ int main(int argc, const char* argv[]) auto tree = ModuleTree {}; tree.load_file(opts.infile); - // Construct argc/argv values - auto val_argc = Value( ::HIR::TypeRef{RawType::ISize} ); - ::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); - // Create argc/argv based on input arguments - val_argc.write_isize(0, 1 + opts.args.size()); 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 }) }); @@ -67,9 +59,13 @@ int main(int argc, const char* argv[]) 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 }) }); } - //val_argv.write_ptr(0, 0, RelocationPtr::new_alloc(argv_alloc)); - val_argv.write_usize(0, 0); - val_argv.allocation->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_alloc(argv_alloc) }); + + // Construct argc/argv values + auto val_argc = Value::new_isize(1 + opts.args.size()); + ::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::new_pointer(argv_ty, 0, RelocationPtr::new_alloc(argv_alloc)); // Catch various exceptions from the interpreter try diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 733aa8a3..c0e7d15c 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -352,16 +352,18 @@ struct MirHelpers LOG_ASSERT(val.m_size == POINTER_SIZE + meta_size, "Deref of " << ty << ", but pointer isn't correct size"); meta_val = ::std::make_shared( val.read_value(POINTER_SIZE, meta_size) ); - // TODO: Get a more sane size from the metadata - if( alloc ) - { + size_t slice_inner_size; + if( ty.has_slice_meta(slice_inner_size) ) { + size = (ty.wrappers.empty() ? 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 - { - size = 0; - } } else { @@ -406,6 +408,7 @@ struct MirHelpers } 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); @@ -428,12 +431,14 @@ struct MirHelpers 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) { @@ -466,11 +471,9 @@ struct MirHelpers 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_ptr(0, 0, RelocationPtr::new_string(&ce)); val.write_usize(POINTER_SIZE, ce.size()); - val.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_string(&ce) }); LOG_DEBUG(c << " = " << val); - //return Value::new_dataptr(ce.data()); return val; } break; // --> Accessor @@ -482,11 +485,8 @@ struct MirHelpers } if( const auto* s = this->thread.m_modtree.get_static_opt(ce) ) { ty = s->ty; - ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); - Value val = Value(ty); - val.write_usize(0, 0); - val.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_alloc(s->val.allocation) }); - return val; + ty.wrappers.insert(ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); + return Value::new_pointer(ty, 0, RelocationPtr::new_alloc(s->val.allocation)); } LOG_ERROR("Constant::ItemAddr - " << ce << " - not found"); } break; @@ -602,19 +602,17 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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(re.type) }); + // Create the pointer new_val = Value(src_ty); - // ^ Pointer value - new_val.write_usize(0, ofs); + 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); } - // - Add the relocation after writing the value (writing clears the relocations) - new_val.allocation->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? @@ -1306,11 +1304,9 @@ bool InterpreterThread::step_one(Value& out_thread_result) size_t ofs = v.m_offset; assert(ty.get_meta_type() == RawType::Unreachable); - auto ptr_ty = ty.wrap(TypeWrapper::Ty::Borrow, 2); + auto ptr_ty = ty.wrapped(TypeWrapper::Ty::Borrow, 2); - auto ptr_val = Value(ptr_ty); - ptr_val.write_usize(0, ofs); - ptr_val.allocation->relocations.push_back(Relocation { 0, ::std::move(alloc) }); + auto ptr_val = Value::new_pointer(ptr_ty, ofs, ::std::move(alloc)); if( !drop_value(ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW) ) { @@ -1327,7 +1323,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_TODO(stmt); break; } - + cur_frame.stmt_idx += 1; } else @@ -1456,7 +1452,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) } cur_frame.stmt_idx = 0; } - + return false; } bool InterpreterThread::pop_stack(Value& out_thread_result) @@ -1465,7 +1461,7 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) 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); @@ -1539,8 +1535,7 @@ bool InterpreterThread::call_path(Value& ret, const ::HIR::Path& path, ::std::ve { if( path == ::HIR::SimplePath { "std", { "sys", "imp", "c", "SetThreadStackGuarantee" } } ) { - ret = Value(::HIR::TypeRef{RawType::I32}); - ret.write_i32(0, 120); // ERROR_CALL_NOT_IMPLEMENTED + ret = Value::new_i32(120); //ERROR_CALL_NOT_IMPLEMENTED return true; } @@ -1552,7 +1547,7 @@ bool InterpreterThread::call_path(Value& ret, const ::HIR::Path& path, ::std::ve ret.write_u64(8, 0); return true; } - + // - No stack overflow handling needed if( path == ::HIR::SimplePath { "std", { "sys", "imp", "stack_overflow", "imp", "init" } } ) { @@ -1567,7 +1562,7 @@ bool InterpreterThread::call_path(Value& ret, const ::HIR::Path& path, ::std::ve // 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; } @@ -1586,10 +1581,8 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c ::HIR::TypeRef rty { RawType::Unit }; rty.wrappers.push_back({ TypeWrapper::Ty::Pointer, 0 }); - rv = Value(rty); - rv.write_usize(0, 0); // TODO: Use the alignment when making an allocation? - rv.allocation->relocations.push_back({ 0, RelocationPtr::new_alloc(Allocation::new_alloc(size)) }); + rv = Value::new_pointer(rty, 0, RelocationPtr::new_alloc(Allocation::new_alloc(size))); } else if( link_name == "__rust_reallocate" ) { @@ -1632,13 +1625,12 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c 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 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(::HIR::TypeRef(RawType::U32)); - out_rv.write_u32(0, 0); + out_rv = Value::new_u32(0); return true; })); @@ -1667,8 +1659,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c else if( link_name == "AddVectoredExceptionHandler" ) { LOG_DEBUG("Call `AddVectoredExceptionHandler` - Ignoring and returning non-null"); - rv = Value(::HIR::TypeRef(RawType::USize)); - rv.write_usize(0, 1); + rv = Value::new_usize(1); } else if( link_name == "GetModuleHandleW" ) { @@ -1732,8 +1723,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c ssize_t val = write(fd, buf, count); - rv = Value(::HIR::TypeRef(RawType::ISize)); - rv.write_isize(0, val); + rv = Value::new_isize(val); } else if( link_name == "sysconf" ) { @@ -1742,33 +1732,27 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c long val = sysconf(name); - rv = Value(::HIR::TypeRef(RawType::USize)); - rv.write_usize(0, val); + 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(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); + rv = Value::new_i32(0); } else if( link_name == "pthread_rwlock_rdlock" ) { - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); + rv = Value::new_i32(0); } else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" ) { - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); + rv = Value::new_i32(0); } else if( link_name == "pthread_condattr_init" || link_name == "pthread_condattr_destroy" || link_name == "pthread_condattr_setclock" ) { - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); + rv = Value::new_i32(0); } else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) { - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); + rv = Value::new_i32(0); } else if( link_name == "pthread_key_create" ) { @@ -1776,9 +1760,8 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c auto key = ThreadState::s_next_tls_key ++; key_ref.m_alloc.alloc().write_u32( key_ref.m_offset, key ); - - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); + + rv = Value::new_i32(0); } else if( link_name == "pthread_getspecific" ) { @@ -1787,8 +1770,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c // Get a pointer-sized value from storage uint64_t v = key < m_thread.tls_values.size() ? m_thread.tls_values[key] : 0; - rv = Value(::HIR::TypeRef(RawType::USize)); - rv.write_usize(0, v); + rv = Value::new_usize(v); } else if( link_name == "pthread_setspecific" ) { @@ -1801,13 +1783,11 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c } m_thread.tls_values[key] = v; - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); + rv = Value::new_i32(0); } else if( link_name == "pthread_key_delete" ) { - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, 0); + rv = Value::new_i32(0); } #endif // std C diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index c3db284a..c1098d1d 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -499,6 +499,11 @@ 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_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) +{ + 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) { auto flags = os.flags(); @@ -620,6 +625,34 @@ Value Value::new_ffiptr(FFIPointer ffi) 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.wrappers.empty()); + assert(ty.wrappers[0].type == TypeWrapper::Ty::Borrow || ty.wrappers[0].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; +} void Value::create_allocation() { @@ -775,6 +808,14 @@ void Value::write_value(size_t ofs, Value v) } } } +void Value::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) +{ + 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) { diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 81302e67..b057b3c4 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -201,6 +201,7 @@ struct ValueCommonWrite: 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(v)); } + virtual void write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) = 0; }; class Allocation: @@ -245,6 +246,7 @@ public: void write_value(size_t ofs, Value v); 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); @@ -254,7 +256,8 @@ struct Value: // If NULL, data is direct 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; @@ -265,8 +268,11 @@ struct Value: 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_usize(uint64_t v); - //static Value new_isize(int64_t v); + 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->size() : direct_data.size; } @@ -289,7 +295,7 @@ struct Value: void write_value(size_t ofs, Value v); 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); + void write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) override; }; extern ::std::ostream& operator<<(::std::ostream& os, const Value& v); -- cgit v1.2.3 From d97d3a3e9fedb73c612fae542db28626a687ab22 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 May 2018 13:29:22 +0800 Subject: Standalone MIRI - Remove direct uses of TypeRef.wrappers --- tools/standalone_miri/hir_sim.cpp | 40 +++++- tools/standalone_miri/hir_sim.hpp | 30 ++++- tools/standalone_miri/main.cpp | 4 +- tools/standalone_miri/miri.cpp | 240 ++++++++++++++++------------------ tools/standalone_miri/module_tree.cpp | 18 +-- tools/standalone_miri/value.cpp | 37 +----- 6 files changed, 186 insertions(+), 183 deletions(-) diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 94f0d0e1..35f8f608 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 +#include #include "hir_sim.hpp" #include "module_tree.hpp" @@ -140,7 +145,32 @@ HIR::TypeRef HIR::TypeRef::wrap(TypeWrapper::Ty ty, size_t size)&& 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 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( this->wrappers.empty() ) { @@ -153,7 +183,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; diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp index 9f5ba59c..7730ac48 100644 --- a/tools/standalone_miri/hir_sim.hpp +++ b/tools/standalone_miri/hir_sim.hpp @@ -118,15 +118,41 @@ namespace HIR { } size_t get_size(size_t ofs=0) 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 - const TypeRef* get_usized_type(size_t& running_inner_size) const; + // 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; + + // 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& other_idx, TypeRef& ty) const; bool operator==(const RawType& x) const { if( this->wrappers.size() != 0 ) @@ -152,8 +178,6 @@ namespace HIR { return false; } - size_t get_field_ofs(size_t idx, const ::std::vector& other_idx, TypeRef& ty) const; - friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& x); }; diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index e3a8d22e..90b5eff3 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -62,9 +62,7 @@ int main(int argc, const char* argv[]) // Construct argc/argv values auto val_argc = Value::new_isize(1 + opts.args.size()); - ::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 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)); // Catch various exceptions from the interpreter diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index c0e7d15c..63be419c 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -175,7 +175,7 @@ public: static PrimitiveValueVirt from_value(const ::HIR::TypeRef& t, const ValueRef& v) { PrimitiveValueVirt rv; - LOG_ASSERT(t.wrappers.empty(), "PrimitiveValueVirt::from_value: " << t); + LOG_ASSERT(t.get_wrapper() == nullptr, "PrimitiveValueVirt::from_value: " << t); switch(t.inner_type) { case RawType::U32: @@ -281,15 +281,18 @@ struct MirHelpers 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() ) + const auto* wrapper = array_ty.get_wrapper(); + if( !wrapper ) + { LOG_ERROR("Indexing non-array/slice - " << array_ty); - if( array_ty.wrappers.front().type == TypeWrapper::Ty::Array ) + } + 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( array_ty.wrappers.front().type == TypeWrapper::Ty::Slice ) + else if( wrapper->type == TypeWrapper::Ty::Slice ) { LOG_TODO("Slice index"); } @@ -354,7 +357,7 @@ struct MirHelpers size_t slice_inner_size; if( ty.has_slice_meta(slice_inner_size) ) { - size = (ty.wrappers.empty() ? ty.get_size() : 0) + meta_val->read_usize(0) * 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 @@ -468,8 +471,7 @@ struct MirHelpers LOG_TODO("Constant::Bytes"); } break; TU_ARM(c, StaticString, ce) { - ty = ::HIR::TypeRef(RawType::Str); - ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); + 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()); @@ -484,8 +486,7 @@ struct MirHelpers return Value::new_fnptr(ce); } if( const auto* s = this->thread.m_modtree.get_static_opt(ce) ) { - ty = s->ty; - ty.wrappers.insert(ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, 0 }); + 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"); @@ -602,10 +603,10 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_DEBUG("- alloc=" << alloc); size_t ofs = src_base_value.m_offset; const auto meta = src_ty.get_meta_type(); - src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast(re.type) }); + auto dst_ty = src_ty.wrapped(TypeWrapper::Ty::Borrow, static_cast(re.type)); // Create the pointer - new_val = Value(src_ty); + new_val = Value(dst_ty); new_val.write_ptr(0, ofs, ::std::move(alloc)); // - Add metadata if required if( meta != RawType::Unreachable ) @@ -626,26 +627,24 @@ bool InterpreterThread::step_one(Value& out_thread_result) // No-op cast new_val = src_value.read_value(0, re.type.get_size()); } - else if( !re.type.wrappers.empty() ) + else if( const auto* dst_w = re.type.get_wrapper() ) { // Destination can only be a raw pointer - if( re.type.wrappers.at(0).type != TypeWrapper::Ty::Pointer ) { - throw "ERROR"; + if( dst_w->type != TypeWrapper::Ty::Pointer ) { + LOG_ERROR("Attempting to cast to a type other than a raw pointer - " << re.type); } - if( !src_ty.wrappers.empty() ) + if( const auto* src_w = src_ty.get_wrapper() ) { // 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_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() ) { - // 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()); + if( src_ty.get_size() < re.type.get_size() ) + { + LOG_ERROR("Casting to a fatter pointer, " << src_ty << " -> " << re.type); } - else + else { new_val = src_value.read_value(0, re.type.get_size()); } @@ -660,18 +659,15 @@ bool InterpreterThread::step_one(Value& out_thread_result) } else { - ::std::cerr << "ERROR: Trying to pointer (" << re.type <<" ) from invalid type (" << src_ty << ")\n"; - throw "ERROR"; + 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( !src_ty.wrappers.empty() ) + else if( const auto* src_w = src_ty.get_wrapper() ) { - // 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"; + 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? @@ -802,7 +798,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_ASSERT(dt.variants[i].field_path.empty(), ""); } ::HIR::TypeRef tag_ty = dt.fields[0].second; - LOG_ASSERT(tag_ty.wrappers.empty(), ""); + LOG_ASSERT(tag_ty.get_wrapper() == nullptr, ""); switch(tag_ty.inner_type) { case RawType::USize: @@ -954,7 +950,33 @@ bool InterpreterThread::step_one(Value& out_thread_result) } LOG_DEBUG("res=" << res << ", " << reloc_l << " ? " << reloc_r); - if( ty_l.wrappers.empty() ) + 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) { @@ -972,29 +994,6 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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 = 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); - } bool res_bool; switch(re.op) { @@ -1013,8 +1012,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) } 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); + 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(v); }; @@ -1051,7 +1050,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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); + LOG_ASSERT(ty_l.get_wrapper() == nullptr, "Bitwise operator on non-primitive - " << ty_l); new_val = Value(ty_l); switch(ty_l.inner_type) { @@ -1104,7 +1103,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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); + LOG_ASSERT(ty.get_wrapper() == nullptr, "UniOp on wrapped type - " << ty); new_val = Value(ty); switch(re.op) { @@ -1238,7 +1237,6 @@ bool InterpreterThread::step_one(Value& out_thread_result) const auto& data_ty = this->m_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) @@ -1250,7 +1248,6 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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; @@ -1279,7 +1276,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) } } break; } - LOG_DEBUG("- " << new_val); + LOG_DEBUG("- new_val=" << new_val); state.write_lvalue(se.dst, ::std::move(new_val)); } break; case ::MIR::Statement::TAG_Asm: @@ -1352,8 +1349,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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); + 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; @@ -1578,8 +1575,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c 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 }); + 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))); @@ -2051,14 +2047,14 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con // 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) ) + 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( !ity->wrappers.empty() ) + if( const auto* w = ity->get_wrapper() ) { - LOG_ASSERT(ity->wrappers[0].type == TypeWrapper::Ty::Slice, ""); + 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; @@ -2088,40 +2084,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con { 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: - // TODO: Only &move has a destructor - 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 ++) - { - // TODO: Nested calls? - if( !drop_value(ptr, ity) ) - { - LOG_DEBUG("Handle multiple queued calls"); - } - ptr.write_usize(0, ptr.read_usize(0) + item_size); - } - } - else - { - return drop_value(val, ty); - } + return drop_value(val, ty); } // ---------------------------------------------------------------- // Checked arithmatic @@ -2249,12 +2212,55 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ 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( ty.wrappers.empty() ) + if( const auto* w = ty.get_wrapper() ) + { + switch( w->type ) + { + case TypeWrapper::Ty::Borrow: + if( w->size == static_cast(::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(::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 ) { @@ -2279,29 +2285,5 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ // No destructor } } - else - { - switch( ty.wrappers[0].type ) - { - case TypeWrapper::Ty::Borrow: - if( ty.wrappers[0].size == static_cast(::HIR::BorrowType::Move) ) - { - LOG_TODO("Drop - " << ty << " - dereference and go to inner"); - // TODO: Clear validity on the entire inner value. - } - else - { - // No destructor - } - break; - case TypeWrapper::Ty::Pointer: - // No destructor - break; - // TODO: Arrays - default: - LOG_TODO("Drop - " << ty << " - array?"); - break; - } - } return true; } diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index cb6f943d..db5fd495 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -266,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); //} @@ -1130,14 +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 { - 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('!') ) { @@ -1152,9 +1152,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(bt) }); - return rv; + return parse_type().wrap( TypeWrapper::Ty::Borrow, static_cast(bt) ); } else if( lex.consume_if('*') ) { @@ -1167,9 +1165,7 @@ 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(bt) }); - return rv; + return parse_type().wrap( TypeWrapper::Ty::Pointer, static_cast(bt) ); } else if( lex.next() == "::" ) { diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index c1098d1d..cf378077 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -545,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"); @@ -586,7 +560,6 @@ Value::Value(::HIR::TypeRef ty) return ; } } -#endif // Fallback: Make a new allocation //LOG_TRACE(" Creating allocation for " << ty); @@ -626,8 +599,8 @@ Value Value::new_ffiptr(FFIPointer ffi) return rv; } Value Value::new_pointer(::HIR::TypeRef ty, uint64_t v, RelocationPtr r) { - assert(!ty.wrappers.empty()); - assert(ty.wrappers[0].type == TypeWrapper::Ty::Borrow || ty.wrappers[0].type == TypeWrapper::Ty::Pointer); + 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) }); -- cgit v1.2.3 From c2cfe98c96562af2a564a6715fcd6d09c2fa9f9b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 May 2018 13:41:19 +0800 Subject: Standalone MIRI - Clean up more direct uses of TypeRef.wrappers --- tools/standalone_miri/hir_sim.cpp | 207 ++++++++++++++++++++------------------ 1 file changed, 111 insertions(+), 96 deletions(-) diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 35f8f608..88739730 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -18,7 +18,58 @@ 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) { @@ -59,56 +110,15 @@ 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(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) { @@ -122,22 +132,20 @@ bool HIR::TypeRef::has_slice_meta(size_t& out_inner_size) const return (this->inner_type == RawType::Str); } } - else - { - out_inner_size = this->get_size(1); - 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)&& { @@ -172,7 +180,18 @@ bool HIR::TypeRef::has_pointer() const } const HIR::TypeRef* HIR::TypeRef::get_unsized_type(size_t& running_inner_size) const { - if( this->wrappers.empty() ) + if( const auto* w = this->get_wrapper() ) + { + if( w->type == TypeWrapper::Ty::Slice ) + { + return this; + } + else + { + return nullptr; + } + } + else { switch(this->inner_type) { @@ -191,18 +210,21 @@ const HIR::TypeRef* HIR::TypeRef::get_unsized_type(size_t& running_inner_size) c return nullptr; } } - else if( this->wrappers[0].type == TypeWrapper::Ty::Slice ) - { - return this; - } - else - { - return nullptr; - } } HIR::TypeRef HIR::TypeRef::get_meta_type() const { - if( this->wrappers.empty() ) + if( const auto* w = this->get_wrapper() ) + { + if( w->type == TypeWrapper::Ty::Slice ) + { + return TypeRef(RawType::USize); + } + else + { + return TypeRef(RawType::Unreachable); + } + } + else { switch(this->inner_type) { @@ -210,30 +232,38 @@ HIR::TypeRef HIR::TypeRef::get_meta_type() const if( this->composite_type->dst_meta == RawType::Unreachable ) return TypeRef(RawType::Unreachable); return this->composite_type->dst_meta; - case RawType::TraitObject: { - auto rv = ::HIR::TypeRef( this->composite_type ); - rv.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, static_cast(BorrowType::Shared) }); - return rv; - } + case RawType::TraitObject: + return ::HIR::TypeRef(this->composite_type).wrap( TypeWrapper::Ty::Pointer, static_cast(BorrowType::Shared) ); case RawType::Str: return TypeRef(RawType::USize); default: return TypeRef(RawType::Unreachable); } } - else if( this->wrappers[0].type == TypeWrapper::Ty::Slice ) - { - return TypeRef(RawType::USize); - } - else - { - return TypeRef(RawType::Unreachable); - } } 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 ) { @@ -247,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& other_idx, TypeRef& ty) const { -- cgit v1.2.3 From b5b70897015ee70d62ddda9711c256ca7c720e0f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 May 2018 09:49:16 +0800 Subject: Standalone MIRI - A few comment notes --- tools/standalone_miri/miri.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 63be419c..5f9c095f 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1467,7 +1467,7 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) } else { - // Handle callback wrappers (e.g. for __rust_maybe_catch_panic) + // 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)) ) @@ -2201,8 +2201,10 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con 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 where the first pointer is the data pointer -- cgit v1.2.3 From aa4d3c5fc5f45891411eb72188c5383a23683495 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 May 2018 11:42:40 +0800 Subject: General TODO cleanup --- src/hir/from_ast.cpp | 62 +++++++++++++++++++++++++++++++++++++----------- src/resolve/absolute.cpp | 9 +++---- src/trans/target.cpp | 29 ++++++++++------------ 3 files changed, 63 insertions(+), 37 deletions(-) diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index ce9b2490..062b4ff8 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -15,6 +15,7 @@ #include "visitor.hpp" #include #include +#include ::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); @@ -63,7 +64,7 @@ (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; @@ -478,7 +479,7 @@ }; ) ) - throw ::std::runtime_error("TODO: LowerHIR_Pattern"); + throw "unreachable"; } ::HIR::ExprPtr LowerHIR_Expr(const ::std::shared_ptr< ::AST::ExprNode>& e) @@ -722,7 +723,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( ptr->m_value ); return ::HIR::TypeRef::new_array( mv$(inner), size_val ); } @@ -833,7 +836,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::MetaItems& attrs) { TRACE_FUNCTION_F(path); ::HIR::Struct::Data data; @@ -858,10 +861,41 @@ 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(attrs.m_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) }; } @@ -933,7 +967,6 @@ namespace { repr = ::HIR::Enum::Repr::Usize; } else { - // TODO: Other repr types ERROR(Span(), E0000, "Unknown enum repr '" << repr_str << "'"); } } @@ -1031,7 +1064,7 @@ namespace { repr = ::HIR::Union::Repr::C; } else { - // TODO: Error? + ERROR(attrs.m_span, E0000, "Unknown union repr '" << repr_str << "'"); } } @@ -1240,7 +1273,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 +1369,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 +1398,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 +1804,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 +1865,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/resolve/absolute.cpp b/src/resolve/absolute.cpp index aece0032..5e9cb51c 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -714,7 +714,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 +741,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 +787,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 +1180,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 << "[.."<() ); } diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 7aa46b35..e37de2aa 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -445,7 +445,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 +526,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 +682,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 +766,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 +790,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 +802,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 +828,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,7 +873,7 @@ namespace { return true; } } - // Handle the NonZero lang item (TODO: Cleaner?) + // 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); @@ -977,7 +974,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 } @@ -1022,8 +1019,6 @@ namespace { { ASSERT_BUG(sp, max_size == 0, "Zero alignment, but non-zero size"); } - - // TODO: Variants. } } break; TU_ARM(enm.m_data, Value, e) { -- cgit v1.2.3 From 7a4733c76c0391578fe04fde9cfa19698878c81e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 May 2018 12:11:32 +0800 Subject: Minicargo - Quieten build output --- minicargo.mk | 14 +++++++------- tools/common/debug.cpp | 8 ++++++++ tools/common/debug.h | 1 + tools/minicargo/Makefile | 2 +- tools/minicargo/main.cpp | 28 +++++++++++++++++++++++----- 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/minicargo.mk b/minicargo.mk index 0d2d4fb1..db19eab9 100644 --- a/minicargo.mk +++ b/minicargo.mk @@ -45,31 +45,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) $(MINICARGO_FLAGS) - test -e $@ + @test -e $@ $(OUTDIR)libpanic_unwind.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir $(MINICARGO) $(RUSTCSRC)src/libpanic_unwind --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) $(MINICARGO_FLAGS) - test -e $@ + @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) $(MINICARGO_FLAGS) - test -e $@ + @test -e $@ $(OUTDIR)libgetopts.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir $(MINICARGO) $(RUSTCSRC)src/libgetopts --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) $(MINICARGO_FLAGS) - test -e $@ + @test -e $@ # MRustC custom version of libproc_macro $(OUTDIR)libproc_macro.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir $(MINICARGO) lib/libproc_macro --output-dir $(OUTDIR) $(MINICARGO_FLAGS) - test -e $@ + @test -e $@ RUSTC_ENV_VARS := CFG_COMPILER_HOST_TRIPLE=$(RUSTC_TARGET) RUSTC_ENV_VARS += LLVM_CONFIG=$(abspath $(LLVM_CONFIG)) 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 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 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/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/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 { -- cgit v1.2.3 From 1c50e757b45f64ead016d6cd2bf27585ba5dce04 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 May 2018 15:02:17 +0800 Subject: AST - Rename MetaItem and MetaItems to Attribute and AttributeList --- src/ast/ast.cpp | 44 +++++++-------- src/ast/ast.hpp | 69 +++++++++++------------ src/ast/attrs.hpp | 107 +++++++++++++++++++++++------------- src/ast/crate.cpp | 6 +- src/ast/crate.hpp | 2 +- src/ast/dump.cpp | 4 +- src/ast/expr.hpp | 10 ++-- src/expand/cfg.cpp | 20 +++---- src/expand/cfg.hpp | 2 +- src/expand/crate_tags.cpp | 10 ++-- src/expand/derive.cpp | 26 ++++----- src/expand/lang_item.cpp | 8 +-- src/expand/macro_rules.cpp | 6 +- src/expand/mod.cpp | 23 ++++---- src/expand/proc_macro.cpp | 6 +- src/expand/std_prelude.cpp | 10 ++-- src/expand/test.cpp | 6 +- src/hir/from_ast.cpp | 14 ++--- src/include/synext_decorator.hpp | 22 ++++---- src/macro_rules/eval.cpp | 2 +- src/parse/common.hpp | 10 ++-- src/parse/expr.cpp | 8 +-- src/parse/interpolated_fragment.cpp | 8 +-- src/parse/interpolated_fragment.hpp | 4 +- src/parse/root.cpp | 105 +++++++++++++++++++---------------- src/parse/token.cpp | 10 ++-- src/parse/token.hpp | 4 +- src/parse/tokenstream.hpp | 4 +- src/resolve/absolute.cpp | 4 +- 29 files changed, 295 insertions(+), 259 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index a4825a89..641bd633 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -14,8 +14,8 @@ namespace AST { namespace { - ::std::vector clone_mivec(const ::std::vector& v) { - ::std::vector ri; + ::std::vector clone_mivec(const ::std::vector& v) { + ::std::vector ri; ri.reserve(v.size()); for(const auto& i : v) ri.push_back( i.clone() ); @@ -23,19 +23,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 +43,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 +103,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(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(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(mv$(name), Item::make_Static({mv$(v)}), true) ); m_items.back().data.attrs = mv$(attrs); } @@ -301,18 +295,18 @@ void Module::add_item( Named 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( 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( mv$(name), mv$(macro), is_exported ) ); diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 6b729f8c..3d7c2dfb 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -51,14 +51,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 +75,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 +129,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 +152,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 +167,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); } @@ -200,15 +194,18 @@ class Trait ::std::vector< Spanned > m_supertraits; bool m_is_marker; + bool m_is_unsafe; NamedList m_items; public: Trait(): - m_is_marker(false) + m_is_marker(false), + m_is_unsafe(false) {} Trait(GenericParams params, ::std::vector< Spanned > supertraits): m_params( mv$(params) ), m_supertraits( mv$(supertraits) ), - m_is_marker(false) + m_is_marker(false), + m_is_unsafe(false) { } @@ -220,12 +217,14 @@ public: const NamedList& items() const { return m_items; } NamedList& 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 +251,7 @@ TAGGED_UNION_EX(EnumVariantData, (), Value, struct EnumVariant { - MetaItems m_attrs; + AttributeList m_attrs; ::std::string m_name; EnumVariantData m_data; @@ -260,21 +259,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 sub_types): + EnumVariant(AttributeList attrs, ::std::string name, ::std::vector 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 fields): + EnumVariant(AttributeList attrs, ::std::string name, ::std::vector fields): m_attrs( mv$(attrs) ), m_name( ::std::move(name) ), m_data( EnumVariantData::make_Struct( {mv$(fields)} ) ) @@ -380,27 +379,29 @@ public: class ImplDef { - Span m_span; - MetaItems m_attrs; + AttributeList m_attrs; + bool m_is_unsafe; GenericParams m_params; Spanned m_trait; TypeRef m_type; public: - //ImplDef() {} - ImplDef(ImplDef&&) /*noexcept*/ = default; - ImplDef(Span sp, MetaItems attrs, GenericParams params, Spanned trait_type, TypeRef impl_type): - m_span( mv$(sp) ), + ImplDef(AttributeList attrs, GenericParams params, Spanned 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 +427,6 @@ public: private: ImplDef m_def; - Span m_span; ::std::vector< ImplItem > m_items; //NamedList m_types; @@ -434,7 +434,6 @@ private: //NamedList m_statics; public: - //Impl() {} Impl(Impl&&) /*noexcept*/ = default; Impl(ImplDef def): m_def( mv$(def) ) @@ -464,8 +463,6 @@ struct UseStmt ::AST::Path path; ::AST::PathBinding alt_binding; - UseStmt() - {} UseStmt(Span sp, Path p): sp(sp), path(p) @@ -553,9 +550,9 @@ public: ::std::shared_ptr add_anon(); void add_item(Named 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 +606,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..4afbdbc1 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,117 @@ 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 m_items; - - virtual ~MetaItems(); - MetaItems() {} - MetaItems(MetaItems&&) = default; - MetaItems& operator=(MetaItems&&) = default; - MetaItems(const MetaItems&) = delete; - MetaItems(Span sp, ::std::vector items): - m_span( mv$(sp) ), + ::std::vector m_items; + + AttributeList() {} + AttributeList(::std::vector items): m_items( mv$(items) ) { } - void push_back(MetaItem i); + // Move present + AttributeList(AttributeList&&) = default; + AttributeList& operator=(AttributeList&&) = default; + // No copy + AttributeList(const AttributeList&) = delete; + 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( const_cast(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( const_cast(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 sub_items; + ::std::vector 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 items): + Attribute(Span sp, ::std::string name, ::std::vector items): + m_span(::std::move(sp)), m_name(name), - m_data( MetaItemData::make_List({mv$(items)}) ) + m_data( AttributeData::make_List({mv$(items)}) ) { } - MetaItem clone() const; + Attribute(const Attribute& ) = delete; + Attribute& operator=(const Attribute&& ) = delete; + Attribute(Attribute&& ) = default; + Attribute& operator=(Attribute&& ) = default; + Attribute 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& items() const { return m_data.as_List().sub_items; } - ::std::vector& items() { return m_data.as_List().sub_items; } + const ::std::vector& items() const { return m_data.as_List().sub_items; } + ::std::vector& 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..b6336a02 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) { diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp index 2c9a1c35..7572b92f 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,10 +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; } + AttributeList& attrs() { return m_attrs; } static ::std::unique_ptr from_deserialiser(Deserialiser& d); }; @@ -263,7 +263,7 @@ struct ExprNode_Loop: struct ExprNode_Match_Arm { - MetaItems m_attrs; + AttributeList m_attrs; ::std::vector m_patterns; unique_ptr m_cond; @@ -418,7 +418,7 @@ struct ExprNode_StructLiteral: public ExprNode { struct Ent { - MetaItems attrs; + AttributeList attrs; ::std::string name; unique_ptr value; }; 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& expr) const override { + void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, ::std::unique_ptr& 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 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..077c4b70 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -303,7 +303,7 @@ class Deriver_Debug: 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); } @@ -488,7 +488,7 @@ class Deriver_PartialEq: 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); } @@ -667,7 +667,7 @@ class Deriver_PartialOrd: 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); } @@ -910,7 +910,7 @@ class Deriver_Eq: 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); } @@ -1062,7 +1062,7 @@ class Deriver_Ord: 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); } @@ -1294,7 +1294,7 @@ class Deriver_Clone: 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); } @@ -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); } @@ -1573,7 +1573,7 @@ class Deriver_Hash: 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); } @@ -1727,7 +1727,7 @@ class Deriver_RustcEncodable: 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); } @@ -1961,7 +1961,7 @@ class Deriver_RustcDecodable: 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); } @@ -2185,7 +2185,7 @@ static const Deriver* find_impl(const ::std::string& trait_name) } template -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 +2257,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..aa7655e3 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 > g_decorators; ::std::map< ::std::string, ::std::unique_ptr > g_macros; -void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::std::function f); +void Expand_Attrs(const ::AST::AttributeList& attrs, AttrStage stage, ::std::function f); void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST::Path modpath, ::AST::Module& mod, unsigned int first_item = 0); void Expand_Expr(::AST::Crate& crate, LList modstack, AST::Expr& node); void Expand_Expr(::AST::Crate& crate, LList modstack, ::std::shared_ptr& 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 f) +void Expand_Attr(const Span& sp, const ::AST::Attribute& a, AttrStage stage, ::std::function 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 f) +void Expand_Attrs(/*const */::AST::AttributeList& attrs, AttrStage stage, ::std::function 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); }); } @@ -1293,7 +1294,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 +1302,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..cdd13a42 100644 --- a/src/expand/proc_macro.cpp +++ b/src/expand/proc_macro.cpp @@ -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; @@ -609,7 +609,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 +622,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/from_ast.cpp b/src/hir/from_ast.cpp index 062b4ff8..1dbfdad2 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -18,7 +18,7 @@ #include ::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); @@ -836,7 +836,7 @@ namespace { } } -::HIR::Struct LowerHIR_Struct(::HIR::ItemPath path, const ::AST::Struct& ent, const ::AST::MetaItems& attrs) +::HIR::Struct LowerHIR_Struct(::HIR::ItemPath path, const ::AST::Struct& ent, const ::AST::AttributeList& attrs) { TRACE_FUNCTION_F(path); ::HIR::Struct::Data data; @@ -879,7 +879,7 @@ namespace { is_packed = true; } else { - TODO(attrs.m_span, "Handle struct repr '" << repr_str << "'"); + TODO(a.span(), "Handle struct repr '" << repr_str << "'"); } } @@ -900,7 +900,7 @@ namespace { }; } -::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::MetaItems& attrs, ::std::function push_struct) +::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::AttributeList& attrs, ::std::function push_struct) { // 1. Figure out what sort of enum this is (value or data) @@ -1050,7 +1050,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; @@ -1064,7 +1064,7 @@ namespace { repr = ::HIR::Union::Repr::C; } else { - ERROR(attrs.m_span, E0000, "Unknown union repr '" << repr_str << "'"); + ERROR(attr_repr->span(), E0000, "Unknown union repr '" << repr_str << "'"); } } @@ -1186,7 +1186,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; 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& expr) const { unexpected(sp, mi, "expression"); } + virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, ::std::unique_ptr& 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..b2f5e409 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -712,7 +712,7 @@ 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 diff --git a/src/parse/common.hpp b/src/parse/common.hpp index ede08984..1ca86128 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -41,16 +41,16 @@ 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::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..22bf9afc 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -66,7 +66,7 @@ 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; + ::AST::AttributeList node_attrs; Parse_ParentAttrs(lex, node_attrs); (void)node_attrs; // TODO: Use these attributes if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) @@ -98,7 +98,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr(m_ptr); break; case InterpolatedFragment::META: - delete reinterpret_cast(m_ptr); + delete reinterpret_cast(m_ptr); break; case InterpolatedFragment::ITEM: delete reinterpret_cast*>(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(x.m_ptr) << "]"; + os << "meta[" << *reinterpret_cast(x.m_ptr) << "]"; break; case InterpolatedFragment::ITEM: { const auto& named_item = *reinterpret_cast*>(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 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 ); ~InterpolatedFragment(); InterpolatedFragment(Type , ::AST::ExprNode*); diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 8fa72fb3..a57d6844 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -41,10 +41,10 @@ Spanned get_spanned(TokenStream& lex, ::std::function 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) @@ -127,7 +127,7 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true) ::std::vector< ::std::string> lifetimes; GET_CHECK_TOK(tok, lex, TOK_LT); do { - ::AST::MetaItems attrs = Parse_ItemAttrs(lex); + auto attrs = Parse_ItemAttrs(lex); (void)attrs; // TODO: Attributes on generic params switch(GET_TOK(tok, lex)) @@ -198,7 +198,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex) } PUTBACK(tok, lex); - ::AST::MetaItems attrs = Parse_ItemAttrs(lex); + auto attrs = Parse_ItemAttrs(lex); (void)attrs; // TODO: Attributes on generic params GET_TOK(tok, lex); @@ -523,7 +523,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 +547,7 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items) ::std::vector 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 +582,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 +607,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; @@ -662,7 +662,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(); @@ -795,7 +795,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 +823,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,7 +841,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); (void)field_attrs; // TODO^ types.push_back( Parse_Type(lex) ); @@ -862,7 +862,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 +897,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 +924,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 +943,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 +956,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 +969,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 +979,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 +988,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 items; + ::std::vector items; do { if(LOOK_AHEAD(lex) == TOK_PAREN_CLOSE) { GET_TOK(tok, lex); @@ -1013,14 +1016,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 +1060,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 +1105,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 +1122,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); { @@ -1216,7 +1219,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 +1231,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 +1455,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="< { "", 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 +1785,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 +1866,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 +1912,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..6f3bafd9 100644 --- a/src/parse/token.cpp +++ b/src/parse/token.cpp @@ -33,7 +33,7 @@ Token::~Token() delete reinterpret_cast(m_data.as_Fragment()); break; case TOK_INTERPOLATED_META: - delete reinterpret_cast(m_data.as_Fragment()); + delete reinterpret_cast(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(frag.m_ptr)->clone() ); + m_data = new AST::Attribute( reinterpret_cast(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(e)->clone().release(); break; case TOK_INTERPOLATED_META: - rv.m_data = new AST::MetaItem( reinterpret_cast(e)->clone() ); + rv.m_data = new AST::Attribute( reinterpret_cast(e)->clone() ); break; case TOK_INTERPOLATED_ITEM: TODO(m_pos, "clone interpolated item"); - //rv.m_data = new AST::Named( AST::Item( reinterpret_cast(e)->clone() ) ); + //rv.m_data = new AST::Named( AST::Item( reinterpret_cast(e)->clone() ) ); break; default: BUG(m_pos, "Fragment with invalid token type (" << *this << ")"); @@ -553,7 +553,7 @@ SERIALISE_TYPE(Token::, "Token", { os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); break; case TOK_INTERPOLATED_META: - os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); + os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); break; case TOK_INTERPOLATED_ITEM: { const auto& named_item = *reinterpret_cast*>(tok.m_data.as_Fragment()); diff --git a/src/parse/token.hpp b/src/parse/token.hpp index 0ef8f009..71b543fc 100644 --- a/src/parse/token.hpp +++ b/src/parse/token.hpp @@ -47,7 +47,7 @@ namespace AST { class Pattern; class Path; class ExprNode; - class MetaItem; + class Attribute; class Item; template @@ -115,7 +115,7 @@ public: TypeRef& frag_type() { assert(m_type == TOK_INTERPOLATED_TYPE); return *reinterpret_cast( m_data.as_Fragment() ); } AST::Path& frag_path() { assert(m_type == TOK_INTERPOLATED_PATH); return *reinterpret_cast( m_data.as_Fragment() ); } AST::Pattern& frag_pattern() { assert(m_type == TOK_INTERPOLATED_PATTERN); return *reinterpret_cast( m_data.as_Fragment() ); } - AST::MetaItem& frag_meta() { assert(m_type == TOK_INTERPOLATED_META); return *reinterpret_cast( m_data.as_Fragment() ); } + AST::Attribute& frag_meta() { assert(m_type == TOK_INTERPOLATED_META); return *reinterpret_cast( m_data.as_Fragment() ); } ::std::unique_ptr take_frag_node(); ::AST::Named take_frag_item(); 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/resolve/absolute.cpp b/src/resolve/absolute.cpp index 5e9cb51c..2c17592c 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -2069,7 +2069,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()); @@ -2102,7 +2102,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 -- cgit v1.2.3 From 508fe45737e08a6749ddc5f903523dc7b3aaba1a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 May 2018 16:16:20 +0800 Subject: Parse - Cleanup TODOs --- src/macro_rules/eval.cpp | 3 ++- src/parse/expr.cpp | 21 +++++++++++---------- src/parse/root.cpp | 31 ++++++++++--------------------- src/parse/token.cpp | 18 +++++++++++++++--- src/parse/tokenstream.cpp | 2 +- 5 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index b2f5e409..a393ba46 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -715,12 +715,13 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type 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/parse/expr.cpp b/src/parse/expr.cpp index 22bf9afc..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::AttributeList 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; @@ -162,6 +163,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr 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 { } @@ -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: { @@ -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/root.cpp b/src/parse/root.cpp index a57d6844..35da3a76 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -346,9 +346,9 @@ 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 ++; @@ -362,22 +362,16 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_ } 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); + args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, is_mut, TypeRef(ty_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); @@ -486,7 +480,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) ); @@ -645,7 +639,6 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items } while( GET_TOK(tok, lex) == TOK_PLUS ); } - // TODO: Support "for Sized?" if(tok.type() == TOK_RWORD_WHERE) { //if( params.ty_params().size() == 0 ) @@ -747,7 +740,6 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& 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 +762,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& 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 +775,6 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& 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: @@ -842,7 +832,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items) } auto field_attrs = Parse_ItemAttrs(lex); - (void)field_attrs; // TODO^ + (void)field_attrs; // TODO: Store field_attrs types.push_back( Parse_Type(lex) ); } while( GET_TOK(tok, lex) == TOK_COMMA ); @@ -1176,8 +1166,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 ) diff --git a/src/parse/token.cpp b/src/parse/token.cpp index 6f3bafd9..eb5830a2 100644 --- a/src/parse/token.cpp +++ b/src/parse/token.cpp @@ -297,7 +297,7 @@ struct EscapedString { reinterpret_cast(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(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 "#"; diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp index 901312a3..625f12db 100644 --- a/src/parse/tokenstream.cpp +++ b/src/parse/tokenstream.cpp @@ -141,7 +141,7 @@ Ident TokenStream::get_ident(Token tok) const 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); -- cgit v1.2.3 From 134be5198993096ab5216b6d52a8937430c733b0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 May 2018 16:16:30 +0800 Subject: TestRunner - Don't pass -L when there's no dependencies --- tools/testrunner/main.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/testrunner/main.cpp b/tools/testrunner/main.cpp index 63391fc5..c83c9f32 100644 --- a/tools/testrunner/main.cpp +++ b/tools/testrunner/main.cpp @@ -336,6 +336,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,6 +361,13 @@ 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; -- cgit v1.2.3 From de9ecd7a2d70359b34e77ded57e5aa9284345ac5 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 May 2018 22:01:59 +0800 Subject: AST - Refactor lifetime/HRB handling --- src/ast/ast.cpp | 30 +++++++++++++----- src/ast/attrs.hpp | 21 +++++++++++-- src/ast/dump.cpp | 8 ++--- src/ast/generics.hpp | 74 ++++++++++++++++++++++++++++++++++----------- src/ast/path.hpp | 5 +-- src/ast/types.cpp | 33 ++++++++++++++++++-- src/ast/types.hpp | 77 +++++++++++++++++++++++++++++++++++++++++++---- src/expand/derive.cpp | 25 +++++++-------- src/expand/mod.cpp | 8 +++-- src/expand/proc_macro.cpp | 48 ++++++++++++++--------------- src/hir/from_ast.cpp | 57 +++++++++++++++++++++++------------ src/parse/common.hpp | 2 +- src/parse/paths.cpp | 4 +-- src/parse/root.cpp | 52 ++++++++++++++++++-------------- src/parse/tokenstream.cpp | 4 +++ src/parse/types.cpp | 77 ++++++++++++++++++++++++++++++----------------- src/resolve/absolute.cpp | 16 +++++----- 17 files changed, 376 insertions(+), 165 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 641bd633..1a19a10f 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -379,10 +379,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; ), @@ -390,14 +411,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/attrs.hpp b/src/ast/attrs.hpp index 4afbdbc1..1926e96a 100644 --- a/src/ast/attrs.hpp +++ b/src/ast/attrs.hpp @@ -30,8 +30,8 @@ public: // Move present AttributeList(AttributeList&&) = default; AttributeList& operator=(AttributeList&&) = default; - // No copy - AttributeList(const AttributeList&) = delete; + // No copy assign, but explicit copy + explicit AttributeList(const AttributeList&) = default; AttributeList& operator=(const AttributeList&) = delete; // Explicit clone AttributeList clone() const; @@ -97,7 +97,22 @@ public: { } - Attribute(const Attribute& ) = delete; + 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(e.sub_items) }); + ) + ) + } Attribute& operator=(const Attribute&& ) = delete; Attribute(Attribute&& ) = default; Attribute& operator=(Attribute&& ) = default; diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp index b6336a02..73b332c0 100644 --- a/src/ast/dump.cpp +++ b/src/ast/dump.cpp @@ -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/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 m_type_params; - ::std::vector< ::std::string > m_lifetime_params; + ::std::vector m_lifetime_params; ::std::vector m_bounds; public: GenericParams() {} @@ -112,7 +150,7 @@ public: GenericParams clone() const { GenericParams rv; rv.m_type_params = ::std::vector( m_type_params ); // Copy-constructable - rv.m_lifetime_params = m_lifetime_params; + rv.m_lifetime_params = ::std::vector(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& ty_params() const { return m_type_params; } ::std::vector& ty_params() { return m_type_params; } - const ::std::vector< ::std::string>& lft_params() const { return m_lifetime_params; } + const ::std::vector& lft_params() const { return m_lifetime_params; } const ::std::vector& bounds() const { return m_bounds; } ::std::vector& 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/path.hpp b/src/ast/path.hpp index 2126e3b2..0470084b 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -28,6 +28,7 @@ class Static; namespace AST { +class LifetimeRef; class GenericParams; class Crate; class Module; @@ -109,14 +110,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 tys, ::std::vector<::std::pair<::std::string,TypeRef>> a): + PathParams(::std::vector lfts, ::std::vector 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/types.cpp b/src/ast/types.cpp index af99f3d7..8065a3ba 100644 --- a/src/ast/types.cpp +++ b/src/ast/types.cpp @@ -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..49cae373 100644 --- a/src/ast/types.hpp +++ b/src/ast/types.hpp @@ -13,6 +13,63 @@ namespace AST { class ExprNode; class Expr; +class LifetimeParam; +} + +namespace AST { + + // Defined here for dependency reasons + class HigherRankedBounds + { + public: + ::std::vector m_lifetimes; + //::std::vector m_types; + //::std::vector 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; } + + 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 @@ -57,6 +114,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 { }), @@ -94,12 +159,12 @@ TAGGED_UNION(TypeData, None, AST::Path path; }), (TraitObject, struct { - ::std::vector<::std::string> hrls; - ::std::vector traits; + ::std::vector traits; + ::std::vector lifetimes; }), (ErasedType, struct { - ::std::vector<::std::string> hrls; - ::std::vector traits; + ::std::vector traits; + ::std::vector lifetimes; }) ); @@ -215,9 +280,9 @@ public: TypeRef(TagPath(), mv$(sp), mv$(path)) {} - TypeRef( Span sp, ::std::vector<::std::string> hrls, ::std::vector traits ): + TypeRef( Span sp, ::std::vector traits, ::std::vector 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/derive.cpp b/src/expand/derive.cpp index 077c4b70..0e28b6da 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 }) ); } @@ -1563,11 +1563,10 @@ class Deriver_Hash: ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "state"), TypeRef(TypeRef::TagReference(), sp, 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))) ); @@ -1717,11 +1716,10 @@ class Deriver_RustcEncodable: ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "s"), TypeRef(TypeRef::TagReference(), sp, 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))) ); @@ -1951,11 +1949,10 @@ class Deriver_RustcDecodable: ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "d"), TypeRef(TypeRef::TagReference(), sp, 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))) ); diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index aa7655e3..4470b2bb 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -272,13 +272,15 @@ void Expand_Type(::AST::Crate& crate, LList 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); } ) ) @@ -859,6 +861,8 @@ void Expand_GenericParams(::AST::Crate& crate, LList modstac for(auto& bound : params.bounds()) { TU_MATCHA( (bound), (be), + (None, + ), (Lifetime, ), (TypeLifetime, diff --git a/src/expand/proc_macro.cpp b/src/expand/proc_macro.cpp index cdd13a42..28d9f613 100644 --- a/src/expand/proc_macro.cpp +++ b/src/expand/proc_macro.cpp @@ -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 diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 1dbfdad2..6353a0ea 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -28,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; @@ -41,24 +46,26 @@ } 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, @@ -66,8 +73,8 @@ // 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); @@ -755,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, diff --git a/src/parse/common.hpp b/src/parse/common.hpp index 1ca86128..49499c86 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -40,7 +40,7 @@ extern ::std::vector Parse_PathNodes(TokenStream& lex, eParsePath extern AST::PathParams Parse_Path_GenericList(TokenStream& lex); -extern ::std::vector< ::std::string> Parse_HRB(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); 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 types; - ::std::vector< ::std::string> lifetimes; + ::std::vector 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/root.cpp b/src/parse/root.cpp index 35da3a76..2b027bf9 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -119,12 +119,12 @@ 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 { auto attrs = Parse_ItemAttrs(lex); @@ -133,17 +133,25 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true) 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; +} + +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,10 +164,9 @@ 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 ) { @@ -168,17 +175,17 @@ void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_ } )); } 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 ret.add_bound( AST::GenericBound::make_IsTrait({ - checked_type.clone(), mv$(lifetimes), Parse_Path(lex, PATH_GENERIC_TYPE) + mv$(outer_hrbs), checked_type.clone(), mv$(inner_hrls), Parse_Path(lex, PATH_GENERIC_TYPE) }) ); } } while( GET_TOK(tok, lex) == TOK_PLUS ); @@ -199,14 +206,12 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex) PUTBACK(tok, lex); auto attrs = Parse_ItemAttrs(lex); - (void)attrs; // TODO: Attributes on generic params 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 +228,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 +263,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 +275,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 { @@ -355,9 +360,9 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_ 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); @@ -622,6 +627,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items do { if( GET_TOK(tok, lex) == TOK_LIFETIME ) { // TODO: Need a better way of indiciating 'static than just an invalid path + // TODO: Ensure that it's 'static supertraits.push_back( make_spanned( Span(tok.get_pos()), AST::Path() ) ); } else if( tok.type() == TOK_BRACE_OPEN ) { diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp index 625f12db..611df2ff 100644 --- a/src/parse/tokenstream.cpp +++ b/src/parse/tokenstream.cpp @@ -140,6 +140,10 @@ 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(), "get_ident from TOK_INTERPOLATED_IDENT"); } diff --git a/src/parse/types.cpp b/src/parse/types.cpp index 26785cf7..b0b43426 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 === @@ -196,7 +196,7 @@ 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 @@ -262,36 +262,52 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls) return TypeRef(TypeRef::TagFunction(), lex.end_span(ps), 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 traits; - ::std::vector< ::std::string> lifetimes; - do { - if( LOOK_AHEAD(lex) == TOK_LIFETIME ) { - GET_TOK(tok, lex); - lifetimes.push_back( tok.str() ); + ::std::vector traits; + ::std::vector 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 traits; - ::std::vector< ::std::string> lifetimes; + ::std::vector traits; + ::std::vector 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 2c17592c..d05e3bc6 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -1500,24 +1500,24 @@ 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_lifetimes( trait.hrbs.m_lifetimes ); + Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, trait.path); + //context.pop_lifetimes(); } - //context.pop_lifetimes(); ), (ErasedType, - //context.push_lifetimes( e.hrls ); for(auto& trait : e.traits) { - Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, trait); + //context.push_lifetimes( trait.hrbs.m_lifetimes ); + Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, trait.path); + //context.pop_lifetimes(); } - //context.pop_lifetimes(); ) ) } @@ -1683,6 +1683,8 @@ 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 ), -- cgit v1.2.3 From f360a87c6c44f1f32c21b64c7a8a6e530737cbb0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 22 May 2018 20:20:14 +0800 Subject: AST - Add lifetime params to & types --- src/ast/types.cpp | 2 +- src/ast/types.hpp | 5 +++-- src/expand/derive.cpp | 32 ++++++++++++++++---------------- src/parse/root.cpp | 2 +- src/parse/types.cpp | 12 +++++------- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/ast/types.cpp b/src/ast/types.cpp index 8065a3ba..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) diff --git a/src/ast/types.hpp b/src/ast/types.hpp index 49cae373..2490c5e8 100644 --- a/src/ast/types.hpp +++ b/src/ast/types.hpp @@ -140,6 +140,7 @@ TAGGED_UNION(TypeData, None, ::std::vector inner_types; }), (Borrow, struct { + AST::LifetimeRef lifetime; bool is_mut; ::std::unique_ptr inner; }), @@ -242,9 +243,9 @@ public: {} 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): diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index 0e28b6da..e60c228f 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -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 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,7 +295,7 @@ 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(), "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "f"), mv$(f_type) ) ) ); @@ -480,8 +480,8 @@ 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(), "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "v" ), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ) ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); @@ -659,8 +659,8 @@ 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(), "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "v" ), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ) ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); @@ -903,7 +903,7 @@ 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(), "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ) ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); @@ -1054,8 +1054,8 @@ 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(), "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "v"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ) ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); @@ -1287,7 +1287,7 @@ 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(), "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ) ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); @@ -1559,8 +1559,8 @@ 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(), "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "state"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, TypeRef(sp, "H", 0x100|0)) ) ) ); fcn.params().add_ty_param( AST::TypeParam(sp, {}, "H") ); @@ -1712,8 +1712,8 @@ 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(), "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "s"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, TypeRef(sp, "S", 0x100|0)) ) ) ); fcn.params().add_ty_param( AST::TypeParam(sp, {}, "S") ); @@ -1945,8 +1945,8 @@ 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(), "self"), TypeRef(TypeRef::TagReference(), sp, false, AST::LifetimeRef(), TypeRef(sp, "Self", 0xFFFF)) ), + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "d"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, TypeRef(sp, "D", 0x100|0)) ) ) ); fcn.params().add_ty_param( AST::TypeParam(sp, {}, "D") ); diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 2b027bf9..0fcbe63a 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -374,7 +374,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_ GET_TOK(tok, lex); } CHECK_TOK(tok, TOK_RWORD_SELF); - args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, is_mut, TypeRef(ty_sp, "Self", 0xFFFF))) ); + args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, ::std::move(lifetime), is_mut, TypeRef(ty_sp, "Self", 0xFFFF))) ); if( allow_self == false ) throw ParseError::Generic(lex, "Self binding not expected"); diff --git a/src/parse/types.cpp b/src/parse/types.cpp index b0b43426..53c79d3b 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -109,23 +109,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: -- cgit v1.2.3 From 704bb17db9a9610b409d729ac511976ea42514c5 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 24 May 2018 21:07:31 +0800 Subject: HIR - Borrow lifetime annotations included (not actually used or valid) --- src/hir/deserialise.cpp | 11 +++++++++-- src/hir/expr.hpp | 12 ++++-------- src/hir/serialise.cpp | 8 +++++++- src/hir/type.cpp | 2 +- src/hir/type.hpp | 4 +++- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 326debd7..902799c3 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -114,6 +114,7 @@ namespace { } + ::HIR::LifetimeRef deserialise_lifetimeref(); ::HIR::TypeRef deserialise_type(); ::HIR::SimplePath deserialise_simplepath(); ::HIR::PathParams deserialise_pathparams(); @@ -718,6 +719,11 @@ namespace { template<> DEF_D( ::HIR::ExternLibrary, return d.deserialise_extlib(); ) + ::HIR::LifetimeRef HirDeserialiser::deserialise_lifetimeref() + { + return { m_in.read_string() }; + } + ::HIR::TypeRef HirDeserialiser::deserialise_type() { ::HIR::TypeRef rv; @@ -741,13 +747,13 @@ namespace { _(TraitObject, { deserialise_traitpath(), deserialise_vec< ::HIR::GenericPath>(), - "" // TODO: m_lifetime + deserialise_lifetimeref() }) _(ErasedType, { deserialise_path(), static_cast(m_in.read_count()), deserialise_vec< ::HIR::TraitPath>(), - "" // TODO: m_lifetime + deserialise_lifetimeref() }) _(Array, { deserialise_ptr< ::HIR::TypeRef>(), @@ -761,6 +767,7 @@ namespace { deserialise_vec< ::HIR::TypeRef>() ) _(Borrow, { + deserialise_lifetimeref(), static_cast< ::HIR::BorrowType>( m_in.read_tag() ), deserialise_ptr< ::HIR::TypeRef>() }) 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/serialise.cpp b/src/hir/serialise.cpp index f1398aa3..c0b4a082 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -87,6 +87,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_string(lr.name); + } void serialise_type(const ::HIR::TypeRef& ty) { m_out.write_tag( ty.m_data.tag() ); @@ -111,7 +115,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 +124,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 +140,7 @@ namespace { serialise_type(st); ), (Borrow, + serialise(e.lifetime); m_out.write_tag(static_cast(e.type)); serialise_type(*e.inner); ), diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 033e7bf5..0f3ee835 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -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..652abfa8 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -84,6 +84,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const BorrowType& bt); struct LifetimeRef { + // Can either reference a named parameter, or an inferred region ::std::string name; bool operator==(const LifetimeRef& x) const { @@ -178,6 +179,7 @@ public: }), (Tuple, ::std::vector), (Borrow, struct { + ::HIR::LifetimeRef lifetime; ::HIR::BorrowType type; ::std::unique_ptr inner; }), @@ -234,7 +236,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))})); -- cgit v1.2.3 From c9475a45f05f73fc669d784c1ca48c720077af31 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 25 May 2018 19:52:39 +0800 Subject: HIR - No more name in lifetime params --- src/hir/deserialise.cpp | 2 +- src/hir/path.hpp | 1 + src/hir/serialise.cpp | 2 +- src/hir/type.cpp | 8 ++++---- src/hir/type.hpp | 42 +++++++++++++++++++++++++++++++++++++++--- src/hir_typeck/helpers.cpp | 15 ++++++++++----- 6 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 902799c3..6ff1988b 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -721,7 +721,7 @@ namespace { ::HIR::LifetimeRef HirDeserialiser::deserialise_lifetimeref() { - return { m_in.read_string() }; + return { m_in.read_count() }; } ::HIR::TypeRef HirDeserialiser::deserialise_type() 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 m_lifetimes; ::std::vector m_types; PathParams(); diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index c0b4a082..b244764b 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -89,7 +89,7 @@ namespace { void serialise(const ::HIR::LifetimeRef& lr) { - m_out.write_string(lr.name); + m_out.write_count(lr.binding); } void serialise_type(const ::HIR::TypeRef& ty) { diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 0f3ee835..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, diff --git a/src/hir/type.hpp b/src/hir/type.hpp index 652abfa8..480b32c4 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -84,11 +84,47 @@ extern ::std::ostream& operator<<(::std::ostream& os, const BorrowType& bt); struct LifetimeRef { - // Can either reference a named parameter, or an inferred region - ::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; } }; 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, -- cgit v1.2.3 From 4f5053eb77644d69f75b3482a91752684d810bd9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 25 May 2018 21:16:11 +0800 Subject: Resolve - Named lifetimes --- src/ast/types.hpp | 2 ++ src/resolve/absolute.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/src/ast/types.hpp b/src/ast/types.hpp index 2490c5e8..1c06593c 100644 --- a/src/ast/types.hpp +++ b/src/ast/types.hpp @@ -61,6 +61,8 @@ namespace AST { } 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); } diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index d05e3bc6..ceb0e40a 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 + 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 { params.m_lifetimes[i].name(), GenericSlot { GenericSlot::Level::Hrb, static_cast(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 { typs[i].name(), GenericSlot { level, static_cast(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 { lfts[i].name(), GenericSlot { level, static_cast(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); @@ -1432,6 +1459,37 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: // - Helps with cases like PartialOrd, 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(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); @@ -1464,6 +1522,7 @@ void Resolve_Absolute_Type(Context& context, TypeRef& type) Resolve_Absolute_Type(context, t); ), (Borrow, + Resolve_Absolute_Lifetime(context, type.span(), e.lifetime); Resolve_Absolute_Type(context, *e.inner); ), (Pointer, @@ -1507,17 +1566,21 @@ void Resolve_Absolute_Type(Context& context, TypeRef& type) ), (TraitObject, for(auto& trait : e.traits) { - //context.push_lifetimes( trait.hrbs.m_lifetimes ); + context.push( trait.hrbs ); Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, trait.path); - //context.pop_lifetimes(); + context.pop(trait.hrbs); } + for(auto& lft : e.lifetimes) + Resolve_Absolute_Lifetime(context, type.span(),lft); ), (ErasedType, for(auto& trait : e.traits) { - //context.push_lifetimes( trait.hrbs.m_lifetimes ); + context.push( trait.hrbs ); Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, trait.path); - //context.pop_lifetimes(); + context.pop(trait.hrbs); } + for(auto& lft : e.lifetimes) + Resolve_Absolute_Lifetime(context, type.span(), lft); ) ) } @@ -1686,14 +1749,20 @@ void Resolve_Absolute_Generic(Context& context, ::AST::GenericParams& params) (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); -- cgit v1.2.3 From d1bac3ff164ba94dc32b50a8c7648deaa34df3e6 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 25 May 2018 21:16:27 +0800 Subject: Makefile - Remove -Werror --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index 18415510..b93a99b2 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 -- cgit v1.2.3 From c87c4abc60f76d1304d46e9086a3467ae6f53bfe Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 26 May 2018 13:21:05 +0800 Subject: disabled_tests_run-pass.txt - Sort tests based on logical progression --- disabled_tests_run-pass.txt | 104 ++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/disabled_tests_run-pass.txt b/disabled_tests_run-pass.txt index e721b6d3..4bf3b2b7 100644 --- a/disabled_tests_run-pass.txt +++ b/disabled_tests_run-pass.txt @@ -83,42 +83,21 @@ 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 -# 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 +# 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 # ^ # CONST EVAL associated-const-type-parameters # TODO: Associated const referred from associated const @@ -335,22 +314,6 @@ 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 # ^ - # HIR MISC xcrate-associated-type-defaults # type_is_specialisable - Handle missing type in impl(0x17e3018) ::"xcrate_associated_type_defaults"::Foo for () {}, name = Out default-associated-types # ^ @@ -371,4 +334,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 -- cgit v1.2.3 From 8a08a06f31515ed26a1076ffe586de0289dca487 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 26 May 2018 13:23:10 +0800 Subject: Include - Add file/line to ASSERT_BUG --- src/include/debug.hpp | 7 +++++++ src/include/span.hpp | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) 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 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 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) -- cgit v1.2.3 From 65337fa61e005457d35065d32b977939767be43e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 26 May 2018 13:23:27 +0800 Subject: HIR Const Eval - (minor) Clean up useless code, comments on potential changes --- src/hir_conv/constant_evaluation.cpp | 37 +++++++++++------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) 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(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 ) -- cgit v1.2.3 From c361d2d46082684b605a32de647944f9ea6607aa Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 26 May 2018 15:27:43 +0800 Subject: main - Make emiting debug dumps optional --- src/main.cpp | 134 ++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 106 insertions(+), 28 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 212cdfd3..0f325230 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "parse/lex.hpp" #include "parse/parseerror.hpp" #include "ast/ast.hpp" @@ -201,6 +202,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 +361,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 +474,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 +517,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 +559,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 +581,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 +599,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 +625,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); }); @@ -869,6 +899,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_mir = true; + } + else if( optname == "dump-mir" ) { + no_optval(); + this->debug.dump_mir = true; + } else if( optname == "stop-after" ) { get_optval(); if( optval == "parse" ) @@ -1053,6 +1095,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 { -- cgit v1.2.3 From 84392bea7f6f0754f61d5b424129eb5fa809674d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 26 May 2018 16:51:43 +0800 Subject: Codegen C - Don't emit destructor when type doesn't need it --- src/trans/codegen_c.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 59687636..187485dc 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -4670,6 +4670,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(indent_level) }; TU_MATCHA( (ty.m_data), (te), // Impossible -- cgit v1.2.3 From af1ec8a893d33aa974186d06498d0fc81d22ae7b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 May 2018 11:33:04 +0800 Subject: AST - Include HRBs on fn() types, fix minor parsing bug --- src/ast/types.hpp | 8 +++++--- src/parse/root.cpp | 4 +++- src/parse/types.cpp | 8 +++++--- src/resolve/absolute.cpp | 2 ++ 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/ast/types.hpp b/src/ast/types.hpp index 1c06593c..22465593 100644 --- a/src/ast/types.hpp +++ b/src/ast/types.hpp @@ -96,6 +96,7 @@ struct TypeArgRef struct Type_Function { + AST::HigherRankedBounds hrbs; bool is_unsafe; ::std::string m_abi; ::std::unique_ptr m_rettype; @@ -103,7 +104,8 @@ struct Type_Function bool is_variadic; Type_Function() {} - Type_Function(bool is_unsafe, ::std::string abi, ::std::unique_ptr ret, ::std::vector args, bool is_variadic): + Type_Function(AST::HigherRankedBounds hrbs, bool is_unsafe, ::std::string abi, ::std::unique_ptr ret, ::std::vector args, bool is_variadic): + hrbs(mv$(hrbs)), is_unsafe(is_unsafe), m_abi(mv$(abi)), m_rettype(mv$(ret)), @@ -239,9 +241,9 @@ public: m_data(TypeData::make_Tuple({::std::move(inner_types)})) {} struct TagFunction {}; - TypeRef(TagFunction, Span sp, bool is_unsafe, ::std::string abi, ::std::vector args, bool is_variadic, TypeRef ret): + TypeRef(TagFunction, Span sp, AST::HigherRankedBounds hrbs, bool is_unsafe, ::std::string abi, ::std::vector 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 {}; diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 0fcbe63a..0a8d2909 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -183,9 +183,11 @@ void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_ else { PUTBACK(tok, lex); } + 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({ - mv$(outer_hrbs), checked_type.clone(), mv$(inner_hrls), 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 ); diff --git a/src/parse/types.cpp b/src/parse/types.cpp index 53c79d3b..a07e66f8 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -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); @@ -197,7 +196,6 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs) { auto ps = lex.start_span(); - // TODO: HRLs TRACE_FUNCTION; Token tok; @@ -206,11 +204,13 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs) 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 ) { @@ -223,6 +223,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs) abi = "C"; } } + // `fn` CHECK_TOK(tok, TOK_RWORD_FN); ::std::vector args; @@ -248,6 +249,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs) } 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 ) { @@ -257,7 +259,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs) 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, ::AST::HigherRankedBounds hrbs, bool allow_trait_list) diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index ceb0e40a..f114fd78 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -1512,10 +1512,12 @@ 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) -- cgit v1.2.3 From 30783d1e61a83bb680f1231af32004f4c994fea3 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 May 2018 11:34:36 +0800 Subject: Trans - Plannin for dynamic library support --- src/main.cpp | 107 ++++++++++++++++++++++++-------------------- src/trans/codegen_c.cpp | 1 + src/trans/main_bindings.hpp | 7 +++ 3 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0f325230..f3b5a2cc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -670,72 +670,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("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("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("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("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("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("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; } } diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 187485dc..f891d267 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -510,6 +510,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"; 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); -- cgit v1.2.3 From 8120f62d373b8ef87357fbfe4b2fc210e955a2fb Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 May 2018 13:06:19 +0800 Subject: AST - Fix missing handling of `for<>` in a few places --- disabled_tests_run-pass.txt | 8 ++++++-- src/ast/ast.hpp | 8 ++++---- src/hir/from_ast.cpp | 4 ++-- src/parse/root.cpp | 35 +++++++++++++++++++++++++---------- src/resolve/absolute.cpp | 8 +++++--- 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/disabled_tests_run-pass.txt b/disabled_tests_run-pass.txt index 4bf3b2b7..767acc56 100644 --- a/disabled_tests_run-pass.txt +++ b/disabled_tests_run-pass.txt @@ -35,8 +35,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. @@ -154,6 +152,10 @@ 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 @@ -313,6 +315,8 @@ type-id-higher-rank # BUG: type_id returns the same value for `for<'a> fn(&'a 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 +abi-sysv64-arg-passing # ERROR: Empty struct arguments to FFI aren't actually empty +extern-pass-empty # ^ # HIR MISC xcrate-associated-type-defaults # type_is_specialisable - Handle missing type in impl(0x17e3018) ::"xcrate_associated_type_defaults"::Foo for () {}, name = Out diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 3d7c2dfb..5d0201d0 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -191,7 +191,7 @@ public: class Trait { GenericParams m_params; - ::std::vector< Spanned > m_supertraits; + ::std::vector< Spanned > m_supertraits; bool m_is_marker; bool m_is_unsafe; @@ -201,7 +201,7 @@ public: m_is_marker(false), m_is_unsafe(false) {} - Trait(GenericParams params, ::std::vector< Spanned > supertraits): + Trait(GenericParams params, ::std::vector< Spanned > supertraits): m_params( mv$(params) ), m_supertraits( mv$(supertraits) ), m_is_marker(false), @@ -211,8 +211,8 @@ public: const GenericParams& params() const { return m_params; } GenericParams& params() { return m_params; } - const ::std::vector >& supertraits() const { return m_supertraits; } - ::std::vector >& supertraits() { return m_supertraits; } + const ::std::vector >& supertraits() const { return m_supertraits; } + ::std::vector >& supertraits() { return m_supertraits; } const NamedList& items() const { return m_items; } NamedList& items() { return m_items; } diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 6353a0ea..4def1a41 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -1108,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"; diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 0a8d2909..4764c063 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -127,8 +127,12 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true) ::AST::HigherRankedBounds rv; GET_CHECK_TOK(tok, lex, TOK_LT); do { + // Support empty lists and comma-terminated lists + if( lex.lookahead(0) == TOK_GT ) { + GET_TOK(tok, lex); + break; + } auto attrs = Parse_ItemAttrs(lex); - (void)attrs; // TODO: Attributes on generic params switch(GET_TOK(tok, lex)) { @@ -142,6 +146,18 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true) CHECK_TOK(tok, TOK_GT); 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) @@ -170,6 +186,8 @@ void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_ } )); } 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) } )); @@ -623,26 +641,23 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items } // Trait bounds "trait Trait : 'lifetime + OtherTrait + OtherTrait2" - ::std::vector > supertraits; + ::std::vector > supertraits; if(tok.type() == TOK_COLON) { + // TODO: Just add these as `where Self: ` (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 - // TODO: Ensure that it's 'static - 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 ); } diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index f114fd78..46a27c2d 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -2055,12 +2055,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); } } -- cgit v1.2.3 From b11fbc6aeacff03570581ad99f1723ff593f12a9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 May 2018 13:25:37 +0800 Subject: Tests - Clean up some now-passing tests --- disabled_tests_run-pass.txt | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/disabled_tests_run-pass.txt b/disabled_tests_run-pass.txt index 767acc56..62266f00 100644 --- a/disabled_tests_run-pass.txt +++ b/disabled_tests_run-pass.txt @@ -140,18 +140,9 @@ 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 # ^ @@ -263,17 +254,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 # ^ @@ -296,7 +286,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) @@ -306,17 +295,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 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 for () {}, name = Out -- cgit v1.2.3 From 5206b786247238f32a2b5ad8ed7f6d378a1d2d12 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 May 2018 13:33:39 +0800 Subject: Include - Add missing file --- src/include/string_view.hpp | 89 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/include/string_view.hpp 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 +#include // size_t +#include // 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; + } +}; + +} -- cgit v1.2.3 From 00a391895c9be6fa66128dbdeb8a368269960ec8 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 May 2018 14:24:49 +0800 Subject: MIR Optimise - Propagate constants into calls --- src/mir/optimise.cpp | 6 ++++++ 1 file changed, 6 insertions(+) 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; } -- cgit v1.2.3 From 5098d733af5daa569bfb57b2a9a3c521df9aeb06 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 11:19:44 +0800 Subject: Misc - Clean up/triage some tests --- disabled_tests_run-pass.txt | 6 ++---- src/resolve/absolute.cpp | 3 +++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/disabled_tests_run-pass.txt b/disabled_tests_run-pass.txt index 62266f00..63cb8fa2 100644 --- a/disabled_tests_run-pass.txt +++ b/disabled_tests_run-pass.txt @@ -92,8 +92,9 @@ 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 PhantomData as a refutable pattern +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 # ^ @@ -204,9 +205,6 @@ fat-ptr-cast # Array unsize missed issue-20797 # Trait unsize runthrough issue-26905 # Manual CoerceUnsized not working? -# None:: syntax somewhere (TODO) -issue-22546 - # MIR GEN: issue-18352 # append_from_lit - Match literal Borrow issue-11940 # ^ diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 46a27c2d..f5e0d9e5 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -1839,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); ), -- cgit v1.2.3 From 092a639c36b8c64ba5401ffa6c4f1cd4065a0135 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 12:27:16 +0800 Subject: AST - Annotate all patterns with spans --- src/ast/pattern.hpp | 39 ++++---- src/expand/derive.cpp | 228 +++++++++++++++++++++++------------------------ src/expand/mod.cpp | 10 +-- src/parse/pattern.cpp | 80 +++++++++-------- src/parse/root.cpp | 10 ++- src/resolve/absolute.cpp | 6 +- 6 files changed, 194 insertions(+), 179 deletions(-) diff --git a/src/ast/pattern.hpp b/src/ast/pattern.hpp index 583ce351..a5e97c40 100644 --- a/src/ast/pattern.hpp +++ b/src/ast/pattern.hpp @@ -106,40 +106,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(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(new Pattern(::std::move(sub_pattern))) }) ) @@ -147,23 +152,28 @@ public: } struct TagTuple {}; - Pattern(TagTuple, ::std::vector pats): + Pattern(TagTuple, Span sp, ::std::vector 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 pats): + Pattern(TagNamedTuple, Span sp, Path path, ::std::vector 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 +184,6 @@ public: const Span& span() const { return m_span; } - void set_span(Span sp) { m_span = mv$(sp); } Pattern clone() const; diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index e60c228f..f7c8fabc 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -295,8 +295,8 @@ 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, AST::LifetimeRef(), 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))) ); @@ -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 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 > 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,8 +480,8 @@ 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, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), - ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "v" ), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), 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))) ); @@ -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 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,8 +659,8 @@ 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, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), - ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "v" ), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), 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))) ); @@ -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::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 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,7 +903,7 @@ 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, AST::LifetimeRef(), 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))) ); @@ -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 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,8 +1054,8 @@ 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, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), - ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "v"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), 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))) ); @@ -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::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 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,7 +1287,7 @@ 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, AST::LifetimeRef(), 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))) ); @@ -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 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), @@ -1559,8 +1559,8 @@ 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, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), - ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "state"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), 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(sp, {}, "H") ); @@ -1633,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 pats_a; @@ -1643,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, @@ -1658,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), @@ -1712,8 +1712,8 @@ 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, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), - ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "s"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), 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(sp, {}, "S") ); @@ -1741,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 ); } @@ -1830,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 pats_a; @@ -1839,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")), @@ -1859,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 > pats_a; @@ -1869,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$( @@ -1883,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")), @@ -1897,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), @@ -1945,8 +1945,8 @@ 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, AST::LifetimeRef(), TypeRef(sp, "Self", 0xFFFF)) ), - ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "d"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), 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(sp, {}, "D") ); @@ -1971,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 ); } @@ -2112,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), @@ -2134,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), diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 4470b2bb..8e052dfe 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -588,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)) ) ); @@ -605,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, @@ -799,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, 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(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(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(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(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(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 4764c063..68ad570b 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -385,7 +385,6 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_ 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 ) @@ -394,7 +393,8 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_ GET_TOK(tok, lex); } CHECK_TOK(tok, TOK_RWORD_SELF); - args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, ::std::move(lifetime), is_mut, TypeRef(ty_sp, "Self", 0xFFFF))) ); + 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"); @@ -413,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 @@ -421,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); } } @@ -430,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 @@ -438,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 diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index f5e0d9e5..c51cac72 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -1809,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)"); } @@ -1821,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 ); } ), -- cgit v1.2.3 From 49cbfd3f9d42207ebd7bd6613dec075c20e61a52 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 12:58:34 +0800 Subject: Travis CI - Enable OSX builds --- .travis.yml | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0dc40d9a..5af7b34b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,31 +1,40 @@ language: cpp sudo: false -os: linux -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 - - zlib1g-dev - - valgrind + +matrix: + include: + # Linux + - os: linux + env: + - CC=gcc-6 + - CC=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 + - make -f minicargo.mk output/libtest.hir # libstd and hello_world - - CC=gcc-6 make test TAIL_COUNT=2 + - make test TAIL_COUNT=2 # rustc (DISABLED: llvm build) -# - CC=gcc-6 CXX=g++-6 make -f minicargo.mk output/rustc +# - make -f minicargo.mk output/rustc # Tests - - CC=gcc-6 CXX=g++-6 make local_tests -k + - make local_tests -k # - CC=gcc-6 make rust_tests -k # cargo -# - CC=gcc-6 CXX=g++-6 make -f minicargo.mk output/cargo +# - make -f minicargo.mk output/cargo # - cat output/cargo-build/cargo_dbg.txt -- cgit v1.2.3 From 020c4401cdf429cdc50a0cadfa0fc56c5dcf7d93 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 13:18:41 +0800 Subject: Targets - Add a rough OSX target --- src/main.cpp | 22 ++++++++++++++++++---- src/trans/target.cpp | 7 +++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f3b5a2cc..3ce041c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,13 +28,15 @@ #include "expand/cfg.hpp" -// Hacky default target +// Hacky default target detection +// - 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" @@ -45,18 +47,23 @@ # elif defined(__i386__) # define DEFAULT_TARGET_NAME "i586-linux-gnu" # else -# error "Unable to detect a suitable default target (linux-gnu)" +# 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" @@ -67,10 +74,17 @@ # elif defined(__i386__) # define DEFAULT_TARGET_NAME "i686-unknown-openbsd" # else -# error "Unable to detect a suitable default target (OpenBSD)" +# 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 -# error "Unable to detect a suitable default target" +# warning "Unable to detect a suitable default target" +#endif +#ifndef DEFAULT_TARGET_NAME +# define DEFAULT_TARGET_NAME "" #endif int g_debug_indent_level = 0; diff --git a/src/trans/target.cpp b/src/trans/target.cpp index e37de2aa..423665a5 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -331,6 +331,13 @@ namespace ARCH_ARM64 }; } + else if(target_name == "x86_64-apple-macosx") + { + return TargetSpec { + "unix", "macosx", "gnu", CodegenMode::Gnu11, "x86_64-apple-darwin", + ARCH_X86_64 + }; + } else { ::std::cerr << "Unknown target name '" << target_name << "'" << ::std::endl; -- cgit v1.2.3 From 324f429f9cf860981f44758473b98e63acabd144 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 13:54:10 +0800 Subject: Travis CI - Tweak environment --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5af7b34b..682e81c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,9 +6,9 @@ matrix: include: # Linux - os: linux - env: - - CC=gcc-6 - - CC=g++-6 + before_install: + - export CC=gcc-6 + - export CXX=g++-6 addons: apt: sources: -- cgit v1.2.3 From 0a55864132d0b4bcd9d36a0ab3bbeafb1cadf8c8 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 14:11:49 +0800 Subject: OSX Build Tweak - environ definition --- src/expand/proc_macro.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expand/proc_macro.cpp b/src/expand/proc_macro.cpp index 28d9f613..969f75b0 100644 --- a/src/expand/proc_macro.cpp +++ b/src/expand/proc_macro.cpp @@ -24,7 +24,7 @@ # include #endif -#if defined(__OpenBSD__) || defined(__NetBSD__) +#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) extern char **environ; #endif -- cgit v1.2.3 From e7d044feecc783b11b42e7d5fedc28b22f4a6766 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 14:24:33 +0800 Subject: Clang Compile Fix --- src/hir/deserialise.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 6ff1988b..4d47016f 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -721,7 +721,7 @@ namespace { ::HIR::LifetimeRef HirDeserialiser::deserialise_lifetimeref() { - return { m_in.read_count() }; + return { static_cast(m_in.read_count()) }; } ::HIR::TypeRef HirDeserialiser::deserialise_type() -- cgit v1.2.3 From 520cf26fb2fe7498c6c7ff303ae957aa42719405 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 14:46:51 +0800 Subject: Makefile - Only extract debuginfo on gnu targets --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index b93a99b2..28a0a909 100644 --- a/Makefile +++ b/Makefile @@ -303,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) -- cgit v1.2.3 From 50ef0034194c2dc1d2fb5730231c8566f405f1f6 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 14:47:19 +0800 Subject: All - Warning cleanup when built with clang --- src/hir_conv/bind.cpp | 4 ++-- src/hir_conv/expand_type.cpp | 4 ++-- src/hir_expand/closures.cpp | 2 +- src/hir_typeck/helpers.hpp | 2 +- src/mir/from_hir.cpp | 4 ++-- src/mir/main_bindings.hpp | 2 +- src/trans/codegen_mmir.cpp | 1 + src/trans/mangling.hpp | 2 +- 8 files changed, 11 insertions(+), 10 deletions(-) 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/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.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()); - 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/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/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 9755bb8b..3347606c 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -281,6 +281,7 @@ namespace case ::HIR::StructMarkings::DstType::TraitObject: return MetadataType::TraitObject; } + throw ""; } break; TU_ARM(te.binding, Union, tpb) return MetadataType::None; 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 namespace HIR { - class SimplePath; + struct SimplePath; class GenericPath; class Path; class TypeRef; -- cgit v1.2.3 From 02683781cb8b815ce0240fd2afc333c57a0460ba Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 17:17:46 +0800 Subject: HIR Serialise - Explicitly serialise tokens (instead of using ancient code) --- src/ast/path.hpp | 1 - src/hir/deserialise.cpp | 32 +++++++++++++++++++++++--------- src/hir/serialise.cpp | 33 +++++++++++++++++++++++++-------- src/parse/token.hpp | 9 +++++++++ 4 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 0470084b..0cb6fcc8 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include "../include/span.hpp" diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 4d47016f..2b9b3512 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -14,7 +14,7 @@ #include "serialise_lowlevel.hpp" #include -namespace { +//namespace { template struct D @@ -311,15 +311,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( 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(m_in.read_tag()); + return ::Token::Data::make_Integer({ dty, m_in.read_u64c() }); + } + case ::Token::Data::TAG_Float: { + auto dty = static_cast(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(); @@ -1234,7 +1248,7 @@ namespace { return rv; } -} +//} ::HIR::CratePtr HIR_Deserialise(const ::std::string& filename, const ::std::string& loaded_name) { diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index b244764b..00e7aa28 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -12,7 +12,7 @@ #include #include "serialise_lowlevel.hpp" -namespace { +//namespace { class HirSerialiser { ::HIR::serialise::Writer& m_out; @@ -446,14 +446,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) @@ -1011,7 +1028,7 @@ namespace { serialise_type(at.m_default); } }; -} +//} void HIR_Serialise(const ::std::string& filename, const ::HIR::Crate& crate) { diff --git a/src/parse/token.hpp b/src/parse/token.hpp index 71b543fc..2da64bca 100644 --- a/src/parse/token.hpp +++ b/src/parse/token.hpp @@ -59,6 +59,9 @@ class InterpolatedFragment; class Token: public Serialisable { + friend class HirSerialiser; + friend class HirDeserialiser; + TAGGED_UNION(Data, None, (None, struct {}), (String, ::std::string), @@ -77,6 +80,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(); -- cgit v1.2.3 From 44ea3bbb2313f718b220ec24b525bd28248a3d94 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 17:43:28 +0800 Subject: AST - Remove old serialisation code (now all done on HIR) --- src/ast/ast.cpp | 1 - src/ast/ast.hpp | 1 - src/ast/expr.hpp | 2 - src/ast/item.hpp | 6 +- src/ast/pattern.cpp | 20 +-- src/ast/pattern.hpp | 10 +- src/ast/types.hpp | 1 - src/hir/deserialise.cpp | 1 - src/hir/serialise.cpp | 1 - src/include/serialise.hpp | 222 ------------------------------ src/include/serialiser_texttree.hpp | 67 --------- src/macro_rules/macro_rules.hpp | 24 +--- src/macro_rules/mod.cpp | 67 --------- src/main.cpp | 1 - src/parse/token.cpp | 72 ---------- src/parse/token.hpp | 7 +- src/serialise.cpp | 264 ------------------------------------ 17 files changed, 9 insertions(+), 758 deletions(-) delete mode 100644 src/include/serialise.hpp delete mode 100644 src/include/serialiser_texttree.hpp delete mode 100644 src/serialise.cpp diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 1a19a10f..4fdf8f9d 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -8,7 +8,6 @@ #include #include "../parse/parseerror.hpp" #include -#include namespace AST { diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 5d0201d0..241b51d7 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -19,7 +19,6 @@ #include "../parse/tokentree.hpp" #include "types.hpp" -#include #include #include diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp index 7572b92f..f3981db5 100644 --- a/src/ast/expr.hpp +++ b/src/ast/expr.hpp @@ -41,8 +41,6 @@ public: m_attrs = mv$(mi); } AttributeList& attrs() { return m_attrs; } - - static ::std::unique_ptr from_deserialiser(Deserialiser& d); }; typedef ::std::unique_ptr ExprNodeP; 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 -#include +#include 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 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 a5e97c40..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, @@ -196,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 from_deserialiser(Deserialiser& s) { - ::std::unique_ptr 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.hpp b/src/ast/types.hpp index 22465593..b6d9d6f5 100644 --- a/src/ast/types.hpp +++ b/src/ast/types.hpp @@ -7,7 +7,6 @@ #include "coretypes.hpp" #include "ast/path.hpp" #include "ast/macro.hpp" -#include #include namespace AST { diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 2b9b3512..17a93730 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -8,7 +8,6 @@ //#define DISABLE_DEBUG // Disable debug for this function - too hot #include "hir.hpp" #include "main_bindings.hpp" -#include #include #include #include "serialise_lowlevel.hpp" diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index 00e7aa28..55cd579f 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -7,7 +7,6 @@ */ #include "hir.hpp" #include "main_bindings.hpp" -#include #include #include #include "serialise_lowlevel.hpp" 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 -#include -#include -#include -#include - -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 - 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 - Serialiser& operator<<(const ::std::vector& v) - { - start_array(v.size()); - for(const auto& ent : v) - *this << ent; - end_array(); - return *this; - } - template - Serialiser& operator<<(const ::std::shared_ptr& v) - { - *this << v.get(); - if(v.get()) - *this << *v; - return *this; - } - template - Serialiser& operator<<(const ::std::unique_ptr& v) - { - *this << v.get(); - if(v.get()) - *this << *v; - return *this; - } - template - Serialiser& operator<<(const ::std::pair& v) - { - start_array(2); - *this << v.first; - *this << v.second; - end_array(); - return *this; - } - template - Serialiser& operator<<(const ::std::map& 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(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 - void item(::std::vector& 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 - void item(::std::shared_ptr& v) - { - bool present; - - item(present); - - if(present) { - v.reset(new T); - item(*v); - } - else { - v.reset(); - } - } - template - void item(::std::unique_ptr& v) - { - bool present; - - item(present); - - if(present) { - v.reset( T::from_deserialiser(*this).release() ); - } - else { - v.reset(); - } - } - template - void item(::std::pair& v) - { - if(2 != start_array()) - throw ::std::runtime_error("Invalid array size for pair"); - item(v.first); - item(v.second); - end_array(); - } - template - void item(::std::map& v) - { - size_t count = start_array(); - while(count--) { - ::std::pair 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 -#include -#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/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 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 3ce041c4..ca55d6ba 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,6 @@ #include "parse/parseerror.hpp" #include "ast/ast.hpp" #include "ast/crate.hpp" -#include #include #include #include "resolve/main_bindings.hpp" diff --git a/src/parse/token.cpp b/src/parse/token.cpp index eb5830a2..115df135 100644 --- a/src/parse/token.cpp +++ b/src/parse/token.cpp @@ -457,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) { diff --git a/src/parse/token.hpp b/src/parse/token.hpp index 2da64bca..3605679b 100644 --- a/src/parse/token.hpp +++ b/src/parse/token.hpp @@ -9,9 +9,9 @@ #include #include -#include #include "../coretypes.hpp" #include +#include enum eTokenType { @@ -56,8 +56,7 @@ namespace AST { class InterpolatedFragment; -class Token: - public Serialisable +class Token { friend class HirSerialiser; friend class HirDeserialiser; @@ -150,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/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 -#include -#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 - '"<> len; - if( !m_is.good() ) - throw DeserialiseFailure("start_array", "length missing"); - DEBUG("len = "<> 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 = '"< Date: Sat, 2 Jun 2018 17:53:44 +0800 Subject: Minicargo - Tweaked error reporting --- tools/minicargo/build.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 392e6a64..79a3dcff 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -1008,8 +1008,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; } -- cgit v1.2.3 From 8225decdd04b7bae20ad82b20059f0fd6da2abd4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 17:54:02 +0800 Subject: Remove serialise.cpp compile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 28a0a909..1aafecc3 100644 --- a/Makefile +++ b/Makefile @@ -70,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 -- cgit v1.2.3 From 2dcdcf9dec83505dde64d21ff7b35ac16c1cccce Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Jun 2018 20:51:23 +0800 Subject: minicargo - Rough OSX support --- tools/minicargo/build.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 79a3dcff..21d8d809 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -42,9 +42,16 @@ extern int _putenv_s(const char*, const char*); # include # include #endif +#ifdef __APPLE__ +# include +#endif #ifdef _WIN32 # define EXESUF ".exe" +#else +# define EXESUF "" +#endif +#ifdef _WIN32 # ifdef _MSC_VER # define HOST_TARGET "x86_64-windows-msvc" # elif defined(__MINGW32__) @@ -52,10 +59,8 @@ extern int _putenv_s(const char*, const char*); # 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 @@ -549,12 +554,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(); -- cgit v1.2.3 From 6a9a81064ae74b70bc93855ba5a9f39ffc996e1b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Jun 2018 09:46:33 +0800 Subject: Trans - Fix target_os for mac --- src/trans/target.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 423665a5..87b5aa1d 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -334,7 +334,7 @@ namespace else if(target_name == "x86_64-apple-macosx") { return TargetSpec { - "unix", "macosx", "gnu", CodegenMode::Gnu11, "x86_64-apple-darwin", + "unix", "macos", "gnu", CodegenMode::Gnu11, "x86_64-apple-darwin", ARCH_X86_64 }; } -- cgit v1.2.3 From 1c25575621e53757234c1033d3e3ccddc5d86aa6 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Jun 2018 11:02:21 +0800 Subject: Trans - Fix some minor errors from building with clang --- src/trans/codegen_c.cpp | 6 ++++++ src/trans/enumerate.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index f891d267..a4b0387a 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), @@ -819,6 +820,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? 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); ), -- cgit v1.2.3 From 1e8435aa1506c7a77a5748b67a7ff1a1d25e4fb2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Jun 2018 11:06:18 +0800 Subject: Testrunner - Fix compilation on OSX, add optimisation and debuginfo --- tools/testrunner/main.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/testrunner/main.cpp b/tools/testrunner/main.cpp index c83c9f32..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 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()) @@ -374,6 +379,14 @@ int main(int argc, const char* argv[]) 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 { @@ -541,10 +554,11 @@ bool run_executable(const ::helpers::path& exe_name, const ::std::vector(argv.data()), environ); if( rv != 0 ) { - DEBUG("Error in posix_spawn - " << rv); + DEBUG("Error in posix_spawn of " << exe_name << " - " << rv); return false; } -- cgit v1.2.3 From b99e6d0a7581c626d6c31c37487548965df05735 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Jun 2018 11:06:53 +0800 Subject: Travis CI - Stop build if libstd/hello fail to compile --- .travis.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 682e81c2..117746b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,14 +27,15 @@ install: - make -C tools/minicargo script: - - make -f minicargo.mk output/libtest.hir -# libstd and hello_world - - make test TAIL_COUNT=2 -# rustc (DISABLED: llvm build) -# - make -f minicargo.mk output/rustc + - set -e + - make -f minicargo.mk output/libtest.hir # libstd + - make test TAIL_COUNT=2 # hello_world # Tests + - set +e - make local_tests -k # - CC=gcc-6 make rust_tests -k -# 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 -- cgit v1.2.3 From 45023a8b4916de02a77abe23e2a800fc1d2e1d6a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Jun 2018 12:10:54 +0800 Subject: All - Move host target auto-detection to be common between compiler and minicargo --- src/main.cpp | 66 +++----------------------------------------- tools/common/target_detect.h | 66 ++++++++++++++++++++++++++++++++++++++++++++ tools/minicargo/build.cpp | 14 ++-------- tools/minicargo/manifest.cpp | 2 +- 4 files changed, 73 insertions(+), 75 deletions(-) create mode 100644 tools/common/target_detect.h diff --git a/src/main.cpp b/src/main.cpp index ca55d6ba..358de95e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,65 +26,7 @@ #include "trans/target.hpp" #include "expand/cfg.hpp" - -// Hacky default target detection -// - 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 +#include // tools/common/target_detect.h int g_debug_indent_level = 0; bool g_debug_enabled = true; @@ -929,7 +871,7 @@ ProgramParams::ProgramParams(int argc, char *argv[]) } else if( optname == "dump-hir" ) { no_optval(); - this->debug.dump_mir = true; + this->debug.dump_hir = true; } else if( optname == "dump-mir" ) { no_optval(); @@ -943,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); 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/minicargo/build.cpp b/tools/minicargo/build.cpp index 21d8d809..42e19552 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -51,18 +51,8 @@ extern int _putenv_s(const char*, const char*); #else # define EXESUF "" #endif -#ifdef _WIN32 -# 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 HOST_TARGET "x86_64-unknown-netbsd" -#else -# define HOST_TARGET "x86_64-unknown-linux-gnu" -#endif +#include // tools/common/target_detect.h +#define HOST_TARGET DEFAULT_TARGET_NAME /// Class abstracting access to the compiler class Builder 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 // toupper #include "repository.h" - +// TODO: Extract this from the target at runtime #ifdef _WIN32 # define TARGET_NAME "i586-windows-msvc" # define CFG_UNIX false -- cgit v1.2.3 From 65cc0bdcfc0d50da763415cabf1128178f74c934 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Jun 2018 12:12:19 +0800 Subject: Docs - Rough documentation on invoking minicargo/mrustc --- docs/running.md | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/target.md | 4 +- 2 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 docs/running.md 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 ` + - Folder containing `.txt` files that are used as if they were the output from that crate's build script (used for building libstd) +- `--vendor-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 ` + - Specifies the output directory, used for both dependencies and the final binary. +- `--target ` + - Cross-compile for the specified target +- `-L ` + - Add a directory to the crate/library search path +- `-j ` + - 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