diff options
author | John Hodge <tpg@mutabah.net> | 2019-10-26 17:15:23 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2019-10-26 17:15:23 +0800 |
commit | 99904636d2e1e335238552cbb5b8b23dd06b7295 (patch) | |
tree | 5fd6470fb702b2a26253d380d47d5b6fd232607f | |
parent | 7ca04e2d668fa44a1663158f844cb912e396cb32 (diff) | |
parent | ebd8edeb4f1861943cc82d310564b1f592e63272 (diff) | |
download | mrust-99904636d2e1e335238552cbb5b8b23dd06b7295.tar.gz |
Merge remote-tracking branch 'remotes/origin/master' into nightly-1.29
40 files changed, 513 insertions, 165 deletions
diff --git a/.travis.yml b/.travis.yml index 63a7347f..a44cceff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ matrix: - os: linux before_install: - export CC=gcc-6 + - export CC-x86_64-linux-gnu=gcc-6 - export CXX=g++-6 addons: apt: @@ -2,6 +2,9 @@ Mutabah's Rust Compiler _In-progress_ alternative rust compiler. Capable of building a fully-working copy of rustc, but not yet suitable for everyday use. +[](https://ci.appveyor.com/project/thepowersgang/mrustc/branch/master) +[](https://travis-ci.org/thepowersgang/mrustc) + Intro === This project is an attempt at creating a simple rust compiler in C++, with the ultimate goal of being a separate re-implementation. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..3f3f52f0 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,19 @@ +version: 1.0.{build} + +configuration: Release +platform: x64 + +before_build: +- cmd: nuget restore vsproject/mrustc.sln + +build: + project: vsproject/mrustc.sln + verbosity: minimal + +test_script: +# - Download/extract rust 1.19.0 +- appveyor DownloadFile https://static.rust-lang.org/dist/rustc-1.19.0-src.tar.gz +- tar xzf rustc-1.19.0-src.tar.gz +- cmd: cd vsproject +- cmd: call build_std.cmd +- cmd: call run_hello.cmd diff --git a/samples/target_stress_test.toml b/samples/target_stress_test.toml new file mode 100644 index 00000000..c7630567 --- /dev/null +++ b/samples/target_stress_test.toml @@ -0,0 +1,22 @@ +[target] +family = "fake" +os-name = "fakest" +env-name = "faker" + +[backend.c] +variant = "msvc" +target = "x86_64-linux-msvc" +compiler-opts = ["/W:1234",] +linker-opts = ["/K",] + +[arch] +name = "fubar" +pointer-bits = 128 +is-big-endian = true +has-atomic-u8 = false +has-atomic-u16 = false +has-atomic-u32 = false +has-atomic-u64 = false +has-atomic-ptr = false +alignments = { u16 = 1, u32 = 2, u64 = 4, u128 = 8, f32 = 3, f64 = 5, ptr = 16 } + diff --git a/samples/test/issue-mrustc-103.rs b/samples/test/issue-mrustc-103.rs new file mode 100644 index 00000000..f27fe6de --- /dev/null +++ b/samples/test/issue-mrustc-103.rs @@ -0,0 +1,9 @@ +macro_rules! pat { + [$a:expr;$b:expr] => ( + println!("{} {}", $a, $b); + ) +} +fn main() { + pat![4;5]; +} + diff --git a/samples/test/issue-mrustc-77.rs b/samples/test/issue-mrustc-77.rs new file mode 100644 index 00000000..ba916822 --- /dev/null +++ b/samples/test/issue-mrustc-77.rs @@ -0,0 +1,14 @@ +// ignore-test + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit<Storage, Align> +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + storage: Storage, + align: [Align; 0], +} + +fn main() { +} diff --git a/samples/test/zst_use.rs b/samples/test/zst_use.rs new file mode 100644 index 00000000..17e75919 --- /dev/null +++ b/samples/test/zst_use.rs @@ -0,0 +1,12 @@ +// compile-flags: --test + +#[test] +fn zst_enum_variant() { + #[inline(never)] + fn takes_fn<F: Fn( () ) -> Option<()>>(f: F) { + f( () ); + } + + takes_fn( Option::Some ); +} + diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp index a9c82efa..6cfda001 100644 --- a/src/ast/expr.hpp +++ b/src/ast/expr.hpp @@ -636,6 +636,7 @@ struct ExprNode_UniOp: class NodeVisitor { public: + virtual ~NodeVisitor() = default; inline void visit(const unique_ptr<ExprNode>& cnode) { if(cnode.get()) cnode->visit(*this); diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index 0ccda406..a14a12a3 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -156,6 +156,7 @@ struct DeriveOpts /// Interface for derive handlers struct Deriver { + virtual ~Deriver() = default; virtual const char* trait_name() const = 0; virtual AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const = 0; virtual AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const = 0; diff --git a/src/expand/proc_macro.cpp b/src/expand/proc_macro.cpp index 3b23184e..bc882d77 100644 --- a/src/expand/proc_macro.cpp +++ b/src/expand/proc_macro.cpp @@ -1008,7 +1008,7 @@ uint64_t ProcMacroInv::recv_v128u() for(;;) { auto b = recv_u8(); - v |= static_cast<uint64_t>(b) << ofs; + v |= static_cast<uint64_t>(b & 0x7F) << ofs; if( (b & 0x80) == 0 ) break; ofs += 7; diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp index 2ca960e3..c87ae3a7 100644 --- a/src/hir/expr.hpp +++ b/src/hir/expr.hpp @@ -821,6 +821,7 @@ struct ExprNode_Closure: class ExprVisitor { public: + virtual ~ExprVisitor() = default; virtual void visit_node_ptr(::std::unique_ptr<ExprNode>& node_ptr); virtual void visit_node(ExprNode& node); #define NV(nt) virtual void visit(nt& n) = 0; diff --git a/src/hir/expr_ptr.hpp b/src/hir/expr_ptr.hpp index 58fa3762..512921eb 100644 --- a/src/hir/expr_ptr.hpp +++ b/src/hir/expr_ptr.hpp @@ -12,7 +12,7 @@ #include <mir/mir_ptr.hpp> -class Span; +struct Span; namespace HIR { diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 10cb9407..8a374946 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -46,6 +46,7 @@ struct Context class Revisitor { public: + virtual ~Revisitor() = default; virtual const Span& span() const = 0; virtual void fmt(::std::ostream& os) const = 0; virtual bool revisit(Context& context, bool is_fallback) = 0; @@ -6667,13 +6668,8 @@ namespace { if( H::type_is_num(left) && H::type_is_num(right) ) { DEBUG("- Magic inferrence link for binops on numerics"); context.equate_types(sp, res, left); - const auto& right = context.get_type(v.params.m_types.at(0)); - context.equate_types_to_shadow(sp, right); - } - else - { - context.equate_types_to_shadow(sp, right); } + context.equate_types_to_shadow(sp, /*right*/v.params.m_types.at(0)); // RHS, can't use `right` because it might be freed by the above equate. } else { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 08e817de..010df546 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -636,7 +636,7 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) } else #endif - root_ivar.type = box$( mv$(type) ); + root_ivar.type = box$( type ); } this->mark_change(); @@ -1648,7 +1648,7 @@ bool TraitResolution::has_associated_type(const ::HIR::TypeRef& input) const //TRACE_FUNCTION_F(input); TU_MATCH(::HIR::TypeRef::Data, (input.m_data), (e), (Infer, - auto& ty = this->m_ivars.get_type(input); + const auto& ty = this->m_ivars.get_type(input); if( ty != input ) { return this->has_associated_type(ty); } diff --git a/src/include/span.hpp b/src/include/span.hpp index 51c3440c..970a2ad0 100644 --- a/src/include/span.hpp +++ b/src/include/span.hpp @@ -29,9 +29,9 @@ struct ProtoSpan unsigned int start_line; unsigned int start_ofs; }; -class Span +struct Span { -public: +//public: ::std::shared_ptr<Span> outer_span; // Expansion target for macros RcString filename; @@ -47,10 +47,14 @@ public: end_line(end_line), end_ofs(end_ofs) {} - Span(const Span& x); + Span(const Span& x) = default; + Span(Span&& x) = default; Span(const Position& position); Span(); + Span& operator=(const Span& x) = default; + Span& operator=(Span&& x) = default; + void bug(::std::function<void(::std::ostream&)> msg) const; void error(ErrorType tag, ::std::function<void(::std::ostream&)> msg) const; void warning(WarningType tag, ::std::function<void(::std::ostream&)> msg) const; diff --git a/src/include/synext_decorator.hpp b/src/include/synext_decorator.hpp index c910f6c0..88a6258c 100644 --- a/src/include/synext_decorator.hpp +++ b/src/include/synext_decorator.hpp @@ -46,6 +46,7 @@ class ExpandDecorator { void unexpected(const Span& sp, const AST::Attribute& mi, const char* loc_str) const; public: + virtual ~ExpandDecorator() = default; virtual AttrStage stage() const = 0; virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const { unexpected(sp, mi, "crate"); } diff --git a/src/macro_rules/macro_rules_ptr.hpp b/src/macro_rules/macro_rules_ptr.hpp index fdb01fbe..5dbfd032 100644 --- a/src/macro_rules/macro_rules_ptr.hpp +++ b/src/macro_rules/macro_rules_ptr.hpp @@ -14,7 +14,7 @@ class MacroRulesPtr MacroRules* m_ptr; public: MacroRulesPtr(): m_ptr(nullptr) {} - MacroRulesPtr(MacroRules* p): m_ptr(p) {} + MacroRulesPtr(MacroRules* p); MacroRulesPtr(MacroRulesPtr&& x): m_ptr(x.m_ptr) { diff --git a/src/macro_rules/mod.cpp b/src/macro_rules/mod.cpp index e9ecb504..2ad325b8 100644 --- a/src/macro_rules/mod.cpp +++ b/src/macro_rules/mod.cpp @@ -168,10 +168,16 @@ bool is_token_vis(eTokenType tt) { } } +MacroRulesPtr::MacroRulesPtr(MacroRules* p): + m_ptr(p) +{ + //::std::cout << "MRP new " << m_ptr << ::std::endl; +} MacroRulesPtr::~MacroRulesPtr() { if(m_ptr) { + //::std::cout << "MRP delete " << m_ptr << ::std::endl; delete m_ptr; m_ptr = nullptr; } diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index 43ffb097..6a476ef1 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -265,6 +265,7 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex) { case TOK_BRACE_OPEN: close = TOK_BRACE_CLOSE; break; case TOK_PAREN_OPEN: close = TOK_PAREN_CLOSE; break; + case TOK_SQUARE_OPEN: close = TOK_SQUARE_CLOSE; break; default: throw ParseError::Unexpected(lex, tok); } diff --git a/src/main.cpp b/src/main.cpp index 0efddc5f..c722bc73 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,7 @@ TargetVersion gTargetVersion = TargetVersion::Rustc1_29; void init_debug_list() { + g_debug_disable_map.insert( "Target Load" ); g_debug_disable_map.insert( "Parse" ); g_debug_disable_map.insert( "LoadCrates" ); g_debug_disable_map.insert( "Expand" ); @@ -159,6 +160,9 @@ struct ProgramParams bool test_harness = false; + // NOTE: If populated, nothing happens except for loading the target + ::std::string target_saveback; + ::std::vector<const char*> lib_search_dirs; ::std::vector<const char*> libraries; ::std::map<::std::string, ::std::string> crate_overrides; // --extern name=path @@ -217,8 +221,21 @@ int main(int argc, char *argv[]) Cfg_SetValueCb("feature", [¶ms](const ::std::string& s) { return params.features.count(s) != 0; }); - Target_SetCfg(params.target); + CompilePhaseV("Target Load", [&]() { + Target_SetCfg(params.target); + }); + if( params.target_saveback != "") + { + Target_ExportCurSpec(params.target_saveback); + return 0; + } + + if( params.infile == "" ) + { + ::std::cerr << "No input file passed" << ::std::endl; + return 1; + } if( params.test_harness ) { @@ -1100,6 +1117,13 @@ ProgramParams::ProgramParams(int argc, char *argv[]) } this->target = argv[++i]; } + else if( strcmp(arg, "--dump-target-spec") == 0 ) { + if (i == argc - 1) { + ::std::cerr << "Flag " << arg << " requires an argument" << ::std::endl; + exit(1); + } + this->target_saveback = argv[++i]; + } else if( strcmp(arg, "--test") == 0 ) { this->test_harness = true; } @@ -1110,12 +1134,6 @@ ProgramParams::ProgramParams(int argc, char *argv[]) } } - if (this->infile == "") - { - ::std::cerr << "No input file passed" << ::std::endl; - exit(1); - } - if( const auto* a = getenv("MRUSTC_TARGET_VER") ) { diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index ef2a24aa..6b8bcf79 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -1264,7 +1264,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, void MIR_CleanupCrate(::HIR::Crate& crate) { - ::MIR::OuterVisitor ov { crate, [&](const auto& res, const auto& p, auto& expr_ptr, const auto& args, const auto& ty){ + ::MIR::OuterVisitor ov { crate, [&](const auto& res, const auto& p, ::HIR::ExprPtr& expr_ptr, const auto& args, const auto& ty){ MIR_Cleanup(res, p, expr_ptr.get_mir_or_error_mut(Span()), args, ty); } }; ov.visit_crate(crate); diff --git a/src/parse/token.cpp b/src/parse/token.cpp index 900108ab..f9ecd028 100644 --- a/src/parse/token.cpp +++ b/src/parse/token.cpp @@ -229,6 +229,7 @@ Token Token::clone() const BUG(m_pos, "Fragment with invalid token type (" << *this << ")"); break; } + assert(rv.m_data.is_Fragment()); ) ) return rv; diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp index 957bc673..6f0c57a1 100644 --- a/src/parse/tokenstream.cpp +++ b/src/parse/tokenstream.cpp @@ -125,7 +125,7 @@ ProtoSpan TokenStream::start_span() const Span TokenStream::end_span(ProtoSpan ps) const { auto p = this->getPosition(); - auto rv = Span( ps.filename, ps.start_line, ps.start_ofs, p.line, p.ofs ); + auto rv = Span( ::std::move(ps.filename), ps.start_line, ps.start_ofs, p.line, p.ofs ); rv.outer_span = this->outerSpan(); return rv; } diff --git a/src/rc_string.cpp b/src/rc_string.cpp index 260ba90a..b56f2e62 100644 --- a/src/rc_string.cpp +++ b/src/rc_string.cpp @@ -23,6 +23,8 @@ RcString::RcString(const char* s, unsigned int len): for(unsigned int j = 0; j < len; j ++ ) data_mut[j] = s[j]; data_mut[len] = '\0'; + + //::std::cout << "RcString(" << m_ptr << " \"" << *this << "\") - " << *m_ptr << " (creation)" << ::std::endl; } } RcString::~RcString() @@ -30,7 +32,7 @@ RcString::~RcString() if(m_ptr) { *m_ptr -= 1; - //::std::cout << "RcString(\"" << *this << "\") - " << *m_ptr << " refs left" << ::std::endl; + //::std::cout << "RcString(" << m_ptr << " \"" << *this << "\") - " << *m_ptr << " refs left (drop)" << ::std::endl; if( *m_ptr == 0 ) { delete[] m_ptr; diff --git a/src/span.cpp b/src/span.cpp index 035258d6..7e3968d1 100644 --- a/src/span.cpp +++ b/src/span.cpp @@ -11,15 +11,6 @@ #include <parse/lex.hpp> #include <common.hpp> -Span::Span(const Span& x): - outer_span(x.outer_span), - filename(x.filename), - start_line(x.start_line), - start_ofs(x.start_ofs), - end_line(x.end_line), - end_ofs(x.end_ofs) -{ -} Span::Span(const Position& pos): outer_span(), filename(pos.filename), diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 8ecf988a..8a392f86 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -200,20 +200,23 @@ namespace { m_outfile_path_c(outfile + ".c"), m_of(m_outfile_path_c) { + m_options.emulated_i128 = Target_GetCurSpec().m_backend_c.m_emulated_i128; switch(Target_GetCurSpec().m_backend_c.m_codegen_mode) { case CodegenMode::Gnu11: m_compiler = Compiler::Gcc; - m_options.emulated_i128 = false; - if( Target_GetCurSpec().m_arch.m_pointer_bits < 64 ) + if( Target_GetCurSpec().m_arch.m_pointer_bits < 64 && !m_options.emulated_i128 ) { - m_options.emulated_i128 = true; + WARNING(Span(), W0000, "Potentially misconfigured target, 32-bit targets require i128 emulation"); } m_options.disallow_empty_structs = true; break; case CodegenMode::Msvc: m_compiler = Compiler::Msvc; - m_options.emulated_i128 = true; + if( !m_options.emulated_i128 ) + { + WARNING(Span(), W0000, "Potentially misconfigured target, MSVC requires i128 emulation"); + } m_options.disallow_empty_structs = true; break; } @@ -297,7 +300,7 @@ namespace { // 64-bit bit ops (gcc intrinsics) m_of << "static inline uint64_t __builtin_clz64(uint64_t v) {\n" - << "\treturn (v >> 32 != 0 ? __builtin_clz(v>>32) : 32 + __builtin_clz(v));\n" + << "\treturn ( (v >> 32) != 0 ? __builtin_clz(v>>32) : 32 + __builtin_clz(v));\n" << "}\n" << "static inline uint64_t __builtin_ctz64(uint64_t v) {\n" << "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n" @@ -322,10 +325,10 @@ namespace { << "static inline uint64_t __builtin_popcount(uint64_t v) {\n" << "\treturn (v >> 32 != 0 ? __popcnt64(v>>32) : 32 + __popcnt64(v));\n" << "}\n" - << "static inline int __builtin_ctz(uint32_t v) { int rv; _BitScanReverse(&rv, v); return rv; }\n" - << "static inline int __builtin_clz(uint32_t v) { int rv; _BitScanForward(&rv, v); return rv; }\n" + << "static inline int __builtin_ctz(uint32_t v) { int rv; _BitScanForward(&rv, v); return rv; }\n" + << "static inline int __builtin_clz(uint32_t v) { int rv; _BitScanReverse(&rv, v); return 31 - rv; }\n" << "static inline uint64_t __builtin_clz64(uint64_t v) {\n" - << "\treturn (v >> 32 != 0 ? __builtin_clz(v>>32) : 32 + __builtin_clz(v));\n" + << "\treturn ( (v >> 32) != 0 ? __builtin_clz(v>>32) : 32 + __builtin_clz(v) );\n" << "}\n" << "static inline uint64_t __builtin_ctz64(uint64_t v) {\n" << "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n" @@ -776,13 +779,14 @@ namespace { if( getenv(varname.c_str()) ) { args.push_back( getenv(varname.c_str()) ); } + else if (system(("which " + Target_GetCurSpec().m_backend_c.m_c_compiler + "-gcc" + " >/dev/null 2>&1").c_str()) == 0) { + args.push_back( Target_GetCurSpec().m_backend_c.m_c_compiler + "-gcc" ); + } else if( getenv("CC") ) { args.push_back( getenv("CC") ); } else { - // TODO: Determine if the compiler can't be found, and fall back to `gcc` if that's the case - args.push_back( Target_GetCurSpec().m_backend_c.m_c_compiler + "-gcc" ); - //args.push_back( "gcc" ); + args.push_back("gcc"); } } for( const auto& a : Target_GetCurSpec().m_backend_c.m_compiler_opts ) @@ -1561,7 +1565,7 @@ namespace { assert(1 + union_fields.size() + 1 >= repr->fields.size()); // Make the union! // NOTE: The way the structure generation works is that enum variants are always first, so the field index = the variant index - // TODO: + // TODO: if( !this->type_is_bad_zst(repr->fields[0].ty) || ::std::any_of(union_fields.begin(), union_fields.end(), [this,repr](auto x){ return !this->type_is_bad_zst(repr->fields[x].ty); }) ) { m_of << "\tunion {\n"; @@ -2176,7 +2180,11 @@ namespace { (String, m_of << "{ "; this->print_escaped_string(e); - m_of << ", " << e.size() << "}"; + // TODO: Better type checking? + if( !ty.m_data.is_Array() ) { + m_of << ", " << e.size(); + } + m_of << "}"; ) ) } @@ -2219,9 +2227,8 @@ namespace { m_of << "\\x0" << (unsigned int)static_cast<uint8_t>(v); else m_of << "\\x" << (unsigned int)static_cast<uint8_t>(v); - // If the next character is a hex digit, - // close/reopen the string. - if( isxdigit(*(&v+1)) ) + // If the next character is a hex digit, close/reopen the string. + if( &v < &s.back() && isxdigit(*(&v+1)) ) m_of << "\"\""; } } @@ -3927,7 +3934,7 @@ namespace { m_of << "("; for(unsigned int j = 0; j < e.args.size(); j ++) { if(j != 0) m_of << ","; - m_of << " "; + m_of << " "; if( m_options.disallow_empty_structs && TU_TEST1(e.args[j], LValue, .is_Field()) ) { ::HIR::TypeRef tmp; @@ -4176,7 +4183,7 @@ namespace { void emit_intrinsic_call(const RcString& name, const ::HIR::PathParams& params, const ::MIR::Terminator::Data_Call& e) { const auto& mir_res = *m_mir_res; - enum class Ordering + enum class Ordering { SeqCst, Acquire, @@ -4341,7 +4348,7 @@ namespace { m_of << "*(volatile uint8_t*)"; else m_of << "*(volatile int8_t*)"; - emit_param(e.args.at(0)); + emit_param(e.args.at(0)); switch(op) { case AtomicOp::Add: m_of << " += "; break; diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 97ac00eb..58739805 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -20,6 +20,14 @@ namespace { size_t PTR_BASE = 0x1000; // See matching value in standalone_miri value.hpp + size_t Target_GetSizeOf_Required(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty) + { + size_t size; + bool type_has_size = Target_GetSizeOf(sp, resolve, ty, size); + ASSERT_BUG(sp, type_has_size, "Attempting to get the size of a unsized type"); + return size; + } + template<typename T> struct Fmt { @@ -874,8 +882,7 @@ namespace cur_ofs ++; } emit_literal_as_bytes(le[i], repr->fields[i].ty, out_relocations, base_ofs + cur_ofs); - size_t size; - assert(Target_GetSizeOf(sp, m_resolve, repr->fields[i].ty, size)); + size_t size = Target_GetSizeOf_Required(sp, m_resolve, repr->fields[i].ty); cur_ofs += size; } while(cur_ofs < repr->size) @@ -898,8 +905,7 @@ namespace emit_literal_as_bytes(*le.val, repr->fields[le.idx].ty, out_relocations, base_ofs + cur_ofs); - size_t size; - assert(Target_GetSizeOf(sp, m_resolve, repr->fields[le.idx].ty, size)); + size_t size = Target_GetSizeOf_Required(sp, m_resolve, repr->fields[le.idx].ty); cur_ofs += size; } @@ -914,8 +920,7 @@ namespace auto v = ::HIR::Literal::make_Integer(le.idx); emit_literal_as_bytes(v, repr->fields[ve->field.index].ty, out_relocations, base_ofs + cur_ofs); - size_t size; - assert(Target_GetSizeOf(sp, m_resolve, repr->fields[ve->field.index].ty, size)); + size_t size = Target_GetSizeOf_Required(sp, m_resolve, repr->fields[ve->field.index].ty); cur_ofs += size; } // TODO: Nonzero? @@ -989,8 +994,7 @@ namespace for(const auto& v : lit.as_List()) { emit_literal_as_bytes(v, *te.inner, out_relocations, base_ofs); - size_t size; - assert(Target_GetSizeOf(sp, m_resolve, *te.inner, size)); + size_t size = Target_GetSizeOf(sp, m_resolve, *te.inner, size); base_ofs += size; } } break; diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 5f52912e..9172481a 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -17,22 +17,32 @@ const TargetArch ARCH_X86_64 = { "x86_64", 64, false, - { /*atomic(u8)=*/true, false, true, true, true } + TargetArch::Atomics(/*atomic(u8)=*/true, false, true, true, true), + TargetArch::Alignments(2, 4, 8, 16, 4, 8, 8) }; const TargetArch ARCH_X86 = { "x86", 32, false, - { /*atomic(u8)=*/true, false, true, false, true } + { /*atomic(u8)=*/true, false, true, false, true }, + TargetArch::Alignments(2, 4, /*u64*/4, /*u128*/4, 4, 4, /*ptr*/4) // u128 has the same alignment as u64, which is u32's alignment. And f64 is 4 byte aligned }; const TargetArch ARCH_ARM64 = { "aarch64", 64, false, - { /*atomic(u8)=*/true, true, true, true, true } + { /*atomic(u8)=*/true, true, true, true, true }, + TargetArch::Alignments(2, 4, 8, 16, 4, 8, 8) }; const TargetArch ARCH_ARM32 = { "arm", 32, false, - { /*atomic(u8)=*/true, false, true, false, true } + { /*atomic(u8)=*/true, false, true, false, true }, + TargetArch::Alignments(2, 4, 8, 16, 4, 8, 4) // Note, all types are natively aligned (but i128 will be emulated) +}; +const TargetArch ARCH_M68K = { + "m68k", + 32, true, + { /*atomic(u8)=*/true, false, true, false, true }, + TargetArch::Alignments(2, 2, 2, 2, 2, 2, 2) }; TargetSpec g_target; @@ -108,6 +118,10 @@ namespace { rv.m_arch = ARCH_X86_64; } + else if( key_val.value.as_string() == ARCH_M68K.m_name ) + { + rv.m_arch = ARCH_M68K; + } else { // Error. @@ -150,6 +164,11 @@ namespace check_path_length(key_val, 3); rv.m_backend_c.m_c_compiler = key_val.value.as_string(); } + else if( key_val.path[2] == "emulate-i128" ) + { + check_path_length(key_val, 3); + rv.m_backend_c.m_emulated_i128 = key_val.value.as_bool(); + } else if( key_val.path[2] == "compiler-opts" ) { check_path_length(key_val, 3); @@ -224,6 +243,42 @@ namespace check_path_length(key_val, 2); rv.m_arch.m_atomics.ptr = key_val.value.as_bool(); } + else if( key_val.path[1] == "alignments" ) + { + check_path_length(key_val, 3); + if( key_val.path[2] == "u16" ) + { + rv.m_arch.m_alignments.u16 = key_val.value.as_int(); + } + else if( key_val.path[2] == "u32" ) + { + rv.m_arch.m_alignments.u32 = key_val.value.as_int(); + } + else if( key_val.path[2] == "u64" ) + { + rv.m_arch.m_alignments.u64 = key_val.value.as_int(); + } + else if( key_val.path[2] == "u128" ) + { + rv.m_arch.m_alignments.u128 = key_val.value.as_int(); + } + else if( key_val.path[2] == "f32" ) + { + rv.m_arch.m_alignments.f32 = key_val.value.as_int(); + } + else if( key_val.path[2] == "f64" ) + { + rv.m_arch.m_alignments.f64 = key_val.value.as_int(); + } + else if( key_val.path[2] == "ptr" ) + { + rv.m_arch.m_alignments.ptr = key_val.value.as_int(); + } + else + { + ::std::cerr << "WARNING: Unknown field arch.alignments." << key_val.path[1] << " in " << filename << ::std::endl; + } + } else { ::std::cerr << "WARNING: Unknown field arch." << key_val.path[1] << " in " << filename << ::std::endl; @@ -281,10 +336,10 @@ namespace << "[backend.c]\n" << "variant = \"" << H::c_variant_name(spec.m_backend_c.m_codegen_mode) << "\"\n" << "target = \"" << spec.m_backend_c.m_c_compiler << "\"\n" - << "compiler-opts = [" << spec.m_backend_c.m_compiler_opts << "]\n" - << "linker-opts = [" << spec.m_backend_c.m_linker_opts << "]\n" + << "compiler-opts = ["; for(const auto& s : spec.m_backend_c.m_compiler_opts) of << "\"" << s << "\","; of << "]\n" + << "linker-opts = ["; for(const auto& s : spec.m_backend_c.m_linker_opts) of << "\"" << s << "\","; of << "]\n" << "\n" - << "[arch]" + << "[arch]\n" << "name = \"" << spec.m_arch.m_name << "\"\n" << "pointer-bits = " << spec.m_arch.m_pointer_bits << "\n" << "is-big-endian = " << H::tfstr(spec.m_arch.m_big_endian) << "\n" @@ -293,6 +348,16 @@ namespace << "has-atomic-u32 = " << H::tfstr(spec.m_arch.m_atomics.u32) << "\n" << "has-atomic-u64 = " << H::tfstr(spec.m_arch.m_atomics.u64) << "\n" << "has-atomic-ptr = " << H::tfstr(spec.m_arch.m_atomics.ptr) << "\n" + << "alignments = {" + << " u16 = " << static_cast<int>(spec.m_arch.m_alignments.u16 ) << "," + << " u32 = " << static_cast<int>(spec.m_arch.m_alignments.u32 ) << "," + << " u64 = " << static_cast<int>(spec.m_arch.m_alignments.u64 ) << "," + << " u128 = " << static_cast<int>(spec.m_arch.m_alignments.u128) << "," + << " f32 = " << static_cast<int>(spec.m_arch.m_alignments.f32 ) << "," + << " f64 = " << static_cast<int>(spec.m_arch.m_alignments.f64 ) << "," + << " ptr = " << static_cast<int>(spec.m_arch.m_alignments.ptr ) + << " }\n" + << "\n" ; } TargetSpec init_from_spec_name(const ::std::string& target_name) @@ -307,42 +372,49 @@ namespace else if(target_name == "i586-linux-gnu") { return TargetSpec { - "unix", "linux", "gnu", {CodegenMode::Gnu11, "i586-linux-gnu", BACKEND_C_OPTS_GNU}, + "unix", "linux", "gnu", {CodegenMode::Gnu11, true, "i586-linux-gnu", BACKEND_C_OPTS_GNU}, ARCH_X86 }; } else if(target_name == "x86_64-linux-gnu") { return TargetSpec { - "unix", "linux", "gnu", {CodegenMode::Gnu11, "x86_64-linux-gnu", BACKEND_C_OPTS_GNU}, + "unix", "linux", "gnu", {CodegenMode::Gnu11, false, "x86_64-linux-gnu", BACKEND_C_OPTS_GNU}, ARCH_X86_64 }; } else if(target_name == "arm-linux-gnu") { return TargetSpec { - "unix", "linux", "gnu", {CodegenMode::Gnu11, "arm-elf-eabi", BACKEND_C_OPTS_GNU}, + "unix", "linux", "gnu", {CodegenMode::Gnu11, true, "arm-elf-eabi", BACKEND_C_OPTS_GNU}, ARCH_ARM32 }; } else if(target_name == "aarch64-linux-gnu") { return TargetSpec { - "unix", "linux", "gnu", {CodegenMode::Gnu11, "aarch64-linux-gnu", BACKEND_C_OPTS_GNU}, + "unix", "linux", "gnu", {CodegenMode::Gnu11, false, "aarch64-linux-gnu", BACKEND_C_OPTS_GNU}, ARCH_ARM64 }; } + else if(target_name == "m68k-linux-gnu") + { + return TargetSpec { + "unix", "linux", "gnu", {CodegenMode::Gnu11, true, "m68k-linux-gnu", BACKEND_C_OPTS_GNU}, + ARCH_M68K + }; + } else if(target_name == "i586-windows-gnu") { return TargetSpec { - "windows", "windows", "gnu", {CodegenMode::Gnu11, "mingw32", BACKEND_C_OPTS_GNU}, + "windows", "windows", "gnu", {CodegenMode::Gnu11, true, "mingw32", BACKEND_C_OPTS_GNU}, ARCH_X86 }; } else if(target_name == "x86_64-windows-gnu") { return TargetSpec { - "windows", "windows", "gnu", {CodegenMode::Gnu11, "x86_64-w64-mingw32", BACKEND_C_OPTS_GNU}, + "windows", "windows", "gnu", {CodegenMode::Gnu11, false, "x86_64-w64-mingw32", BACKEND_C_OPTS_GNU}, ARCH_X86_64 }; } @@ -350,84 +422,84 @@ namespace { // TODO: Should this include the "kernel32.lib" inclusion? return TargetSpec { - "windows", "windows", "msvc", {CodegenMode::Msvc, "x86", {}, {}}, + "windows", "windows", "msvc", {CodegenMode::Msvc, true, "x86", {}, {}}, ARCH_X86 }; } else if (target_name == "x86_64-windows-msvc") { return TargetSpec { - "windows", "windows", "msvc", {CodegenMode::Msvc, "amd64", {}, {}}, + "windows", "windows", "msvc", {CodegenMode::Msvc, true, "amd64", {}, {}}, ARCH_X86_64 }; } else if(target_name == "i686-unknown-freebsd") { return TargetSpec { - "unix", "freebsd", "gnu", {CodegenMode::Gnu11, "i686-unknown-freebsd", BACKEND_C_OPTS_GNU}, + "unix", "freebsd", "gnu", {CodegenMode::Gnu11, true, "i686-unknown-freebsd", BACKEND_C_OPTS_GNU}, ARCH_X86 }; } else if(target_name == "x86_64-unknown-freebsd") { return TargetSpec { - "unix", "freebsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-freebsd", BACKEND_C_OPTS_GNU}, + "unix", "freebsd", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-freebsd", BACKEND_C_OPTS_GNU}, ARCH_X86_64 }; } else if(target_name == "arm-unknown-freebsd") { return TargetSpec { - "unix", "freebsd", "gnu", {CodegenMode::Gnu11, "arm-unknown-freebsd", BACKEND_C_OPTS_GNU}, + "unix", "freebsd", "gnu", {CodegenMode::Gnu11, true, "arm-unknown-freebsd", BACKEND_C_OPTS_GNU}, ARCH_ARM32 }; } else if(target_name == "aarch64-unknown-freebsd") { return TargetSpec { - "unix", "freebsd", "gnu", {CodegenMode::Gnu11, "aarch64-unknown-freebsd", BACKEND_C_OPTS_GNU}, + "unix", "freebsd", "gnu", {CodegenMode::Gnu11, false, "aarch64-unknown-freebsd", BACKEND_C_OPTS_GNU}, ARCH_ARM64 }; } else if(target_name == "x86_64-unknown-netbsd") { return TargetSpec { - "unix", "netbsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-netbsd", BACKEND_C_OPTS_GNU}, + "unix", "netbsd", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-netbsd", BACKEND_C_OPTS_GNU}, ARCH_X86_64 }; } else if(target_name == "i686-unknown-openbsd") { return TargetSpec { - "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "i686-unknown-openbsd", BACKEND_C_OPTS_GNU}, + "unix", "openbsd", "gnu", {CodegenMode::Gnu11, true, "i686-unknown-openbsd", BACKEND_C_OPTS_GNU}, ARCH_X86 }; } else if(target_name == "x86_64-unknown-openbsd") { return TargetSpec { - "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-openbsd", BACKEND_C_OPTS_GNU}, + "unix", "openbsd", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-openbsd", BACKEND_C_OPTS_GNU}, ARCH_X86_64 }; } else if(target_name == "arm-unknown-openbsd") { return TargetSpec { - "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "arm-unknown-openbsd", BACKEND_C_OPTS_GNU}, + "unix", "openbsd", "gnu", {CodegenMode::Gnu11, true, "arm-unknown-openbsd", BACKEND_C_OPTS_GNU}, ARCH_ARM32 }; } else if(target_name == "aarch64-unknown-openbsd") { return TargetSpec { - "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "aarch64-unknown-openbsd", BACKEND_C_OPTS_GNU}, + "unix", "openbsd", "gnu", {CodegenMode::Gnu11, false, "aarch64-unknown-openbsd", BACKEND_C_OPTS_GNU}, ARCH_ARM64 }; } else if(target_name == "x86_64-unknown-dragonfly") { return TargetSpec { - "unix", "dragonfly", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-dragonfly", BACKEND_C_OPTS_GNU}, + "unix", "dragonfly", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-dragonfly", BACKEND_C_OPTS_GNU}, ARCH_X86_64 }; } @@ -435,7 +507,21 @@ namespace { // NOTE: OSX uses Mach-O binaries, which don't fully support the defaults used for GNU targets return TargetSpec { - "unix", "macos", "gnu", {CodegenMode::Gnu11, "x86_64-apple-darwin", {}, {}}, + "unix", "macos", "gnu", {CodegenMode::Gnu11, false, "x86_64-apple-darwin", {}, {}}, + ARCH_X86_64 + }; + } + else if(target_name == "arm-unknown-haiku") + { + return TargetSpec { + "unix", "haiku", "gnu", {CodegenMode::Gnu11, true, "arm-unknown-haiku", {}, {}}, + ARCH_ARM32 + }; + } + else if(target_name == "x86_64-unknown-haiku") + { + return TargetSpec { + "unix", "haiku", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-haiku", {}, {}}, ARCH_X86_64 }; } @@ -536,48 +622,45 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, case ::HIR::CoreType::U8: case ::HIR::CoreType::I8: out_size = 1; - out_align = 1; + out_align = 1; // u8 is always 1 aligned return true; case ::HIR::CoreType::U16: case ::HIR::CoreType::I16: out_size = 2; - out_align = 2; + out_align = g_target.m_arch.m_alignments.u16; return true; case ::HIR::CoreType::U32: case ::HIR::CoreType::I32: case ::HIR::CoreType::Char: out_size = 4; - out_align = 4; + out_align = g_target.m_arch.m_alignments.u32; return true; case ::HIR::CoreType::U64: case ::HIR::CoreType::I64: out_size = 8; - // TODO: on x86, u64/i64 has an alignment of 4, while x86_64 has 8. What do other platforms have? - out_align = g_target.m_arch.m_name == "x86" ? 4 : 8; + out_align = g_target.m_arch.m_alignments.u64; return true; case ::HIR::CoreType::U128: case ::HIR::CoreType::I128: out_size = 16; // TODO: If i128 is emulated, this can be 8 (as it is on x86, where it's actually 4 due to the above comment) - if( g_target.m_arch.m_name == "x86" ) - out_align = 4; - else if( /*g_target.m_arch.m_name == "x86_64" && */g_target.m_backend_c.m_codegen_mode == CodegenMode::Msvc ) - out_align = 8; - else - out_align = 16; + if( g_target.m_backend_c.m_emulated_i128 ) + out_align = g_target.m_arch.m_alignments.u64; + else + out_align = g_target.m_arch.m_alignments.u128; return true; case ::HIR::CoreType::Usize: case ::HIR::CoreType::Isize: out_size = g_target.m_arch.m_pointer_bits / 8; - out_align = g_target.m_arch.m_pointer_bits / 8; + out_align = g_target.m_arch.m_alignments.ptr; return true; case ::HIR::CoreType::F32: out_size = 4; - out_align = 4; + out_align = g_target.m_arch.m_alignments.f32; return true; case ::HIR::CoreType::F64: out_size = 8; - out_align = g_target.m_arch.m_name == "x86" ? 4 : 8; + out_align = g_target.m_arch.m_alignments.f64; return true; case ::HIR::CoreType::Str: DEBUG("sizeof on a `str` - unsized"); diff --git a/src/trans/target.hpp b/src/trans/target.hpp index 107d19e1..3433483b 100644 --- a/src/trans/target.hpp +++ b/src/trans/target.hpp @@ -17,23 +17,53 @@ enum class CodegenMode Msvc, }; +// NOTE: The default architecture is an unnamed 32-bit little-endian arch with all types natively aligned struct TargetArch { ::std::string m_name; unsigned m_pointer_bits; bool m_big_endian; - struct { - bool u8; - bool u16; - bool u32; - bool u64; - bool ptr; + struct Atomics { + bool u8 = true; + bool u16 = true; + bool u32 = true; + bool u64 = false; + bool ptr = true; + Atomics(bool u8 = true, bool u16 = true, bool u32 = true, bool u64 = false, bool ptr = true) + :u8(u8) + ,u16(u16) + ,u32(u32) + ,u64(u64) + ,ptr(ptr) + { + } } m_atomics; + + struct Alignments { + uint8_t u16; + uint8_t u32; + uint8_t u64; + uint8_t u128; + uint8_t f32; + uint8_t f64; + uint8_t ptr; + Alignments(uint8_t u16 = 2, uint8_t u32 = 4, uint8_t u64 = 8, uint8_t u128 = 16, uint8_t f32 = 4, uint8_t f64 = 8, uint8_t ptr = 4) + :u16 (u16) + ,u32 (u32 ) + ,u64 (u64 ) + ,u128(u128) + ,f32 (f32 ) + ,f64 (f64 ) + ,ptr (ptr ) + { + } + } m_alignments; }; struct BackendOptsC { CodegenMode m_codegen_mode; + bool m_emulated_i128; // Influences the chosen alignment for i128/u128 ::std::string m_c_compiler; // MSVC arch / GNU triplet ::std::vector< ::std::string> m_compiler_opts; ::std::vector< ::std::string> m_linker_opts; diff --git a/tools/common/path.h b/tools/common/path.h index eae4951f..1ad6f506 100644 --- a/tools/common/path.h +++ b/tools/common/path.h @@ -38,6 +38,13 @@ public: return m_str != ""; } + bool operator==(const path& p) const { + return m_str == p.m_str; + } + bool operator!=(const path& p) const { + return m_str != p.m_str; + } + path& operator/=(const path& p) { if(!p.is_valid()) diff --git a/tools/common/target_detect.h b/tools/common/target_detect.h index a4c44ba4..1bfc7dd9 100644 --- a/tools/common/target_detect.h +++ b/tools/common/target_detect.h @@ -24,6 +24,8 @@ # define DEFAULT_TARGET_NAME "arm-linux-gnu" # elif defined(__i386__) # define DEFAULT_TARGET_NAME "i586-linux-gnu" +# elif defined(__m68k__) +# define DEFAULT_TARGET_NAME "m68k-linux-gnu" # else # warning "Unable to detect a suitable default target (linux-gnu)" # endif @@ -73,6 +75,15 @@ // - Apple devices #elif defined(__APPLE__) # define DEFAULT_TARGET_NAME "x86_64-apple-macosx" +// - Haiku +#elif defined(__HAIKU__) +# if defined(__x86_64__) +# define DEFAULT_TARGET_NAME "x86_64-unknown-haiku" +# elif defined(__arm__) +# define DEFAULT_TARGET_NAME "arm-unknown-haiku" +# else +# warning "Unable to detect a suitable default target (Haiku)" +# endif // - Unknown #else # warning "Unable to detect a suitable default target" diff --git a/tools/common/toml.cpp b/tools/common/toml.cpp index 7e24b610..4e8e6da6 100644 --- a/tools/common/toml.cpp +++ b/tools/common/toml.cpp @@ -80,11 +80,8 @@ struct Token }; TomlFile::TomlFile(const ::std::string& filename): - m_if(filename) + m_lexer(filename) { - if( !m_if.is_open() ) { - throw ::std::runtime_error("Unable to open file '" + filename + "'"); - } } TomlFileIter TomlFile::begin() { @@ -99,12 +96,14 @@ TomlFileIter TomlFile::end() TomlKeyValue TomlFile::get_next_value() { - auto t = Token::lex_from(m_if); + auto t = m_lexer.get_token(); if(m_current_composite.empty()) { while( t.m_type == Token::Type::Newline ) - t = Token::lex_from(m_if); + { + t = m_lexer.get_token(); + } // Expect '[', a string, or an identifier switch(t.m_type) @@ -116,32 +115,32 @@ TomlKeyValue TomlFile::get_next_value() m_current_block.clear(); do { - t = Token::lex_from(m_if); + t = m_lexer.get_token(); bool is_array = false; if(t.m_type == Token::Type::SquareOpen) { is_array = true; - t = Token::lex_from(m_if); + t = m_lexer.get_token(); } assert(t.m_type == Token::Type::Ident || t.m_type == Token::Type::String); m_current_block.push_back(t.as_string()); if(is_array) { m_current_block.push_back(::format(m_array_counts[t.as_string()]++)); - t = Token::lex_from(m_if); + t = m_lexer.get_token(); assert(t.m_type == Token::Type::SquareClose); } - t = Token::lex_from(m_if); + t = m_lexer.get_token(); } while(t.m_type == Token::Type::Dot); if( t.m_type != Token::Type::SquareClose ) { - throw ::std::runtime_error(::format("Unexpected token in block header - ", t)); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in block header - ", t)); } - t = Token::lex_from(m_if); + t = m_lexer.get_token(); if (t.m_type != Token::Type::Newline) { - throw ::std::runtime_error(::format("Unexpected token after block block - ", t)); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected token after block block - ", t)); } DEBUG("Start block " << m_current_block); // Recurse! @@ -156,7 +155,7 @@ TomlKeyValue TomlFile::get_next_value() if( t.m_type == Token::Type::Eof ) { // EOF isn't allowed here - throw ::std::runtime_error(::format("Unexpected EOF in composite")); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected EOF in composite")); } } switch (t.m_type) @@ -165,14 +164,14 @@ TomlKeyValue TomlFile::get_next_value() case Token::Type::Ident: break; default: - throw ::std::runtime_error(::format("Unexpected token for key - ", t)); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected token for key - ", t)); } ::std::string key_name = t.as_string(); - t = Token::lex_from(m_if); + t = m_lexer.get_token(); if(t.m_type != Token::Type::Assign) - throw ::std::runtime_error(::format("Unexpected token after key - ", t)); - t = Token::lex_from(m_if); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected token after key - ", t)); + t = m_lexer.get_token(); // --- Value --- TomlKeyValue rv; @@ -193,10 +192,12 @@ TomlKeyValue TomlFile::get_next_value() rv.path.push_back(key_name); rv.value.m_type = TomlValue::Type::List; - while( (t = Token::lex_from(m_if)).m_type != Token::Type::SquareClose ) + while( (t = m_lexer.get_token()).m_type != Token::Type::SquareClose ) { while( t.m_type == Token::Type::Newline ) - t = Token::lex_from(m_if); + { + t = m_lexer.get_token(); + } if( t.m_type == Token::Type::SquareClose ) break; @@ -208,15 +209,15 @@ TomlKeyValue TomlFile::get_next_value() rv.value.m_sub_values.push_back(TomlValue { t.as_string() }); break; default: - throw ::std::runtime_error(::format("Unexpected token in array value position - ", t)); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in array value position - ", t)); } - t = Token::lex_from(m_if); + t = m_lexer.get_token(); if(t.m_type != Token::Type::Comma) break; } if(t.m_type != Token::Type::SquareClose) - throw ::std::runtime_error(::format("Unexpected token after array - ", t)); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected token after array - ", t)); break; case Token::Type::BraceOpen: m_current_composite.push_back(key_name); @@ -228,7 +229,7 @@ TomlKeyValue TomlFile::get_next_value() rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end()); rv.path.push_back(key_name); rv.value = TomlValue { t.m_intval }; - return rv; + break; case Token::Type::Ident: if( t.m_data == "true" ) { @@ -247,33 +248,57 @@ TomlKeyValue TomlFile::get_next_value() } else { - throw ::std::runtime_error(::format("Unexpected identifier in value position - ", t)); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected identifier in value position - ", t)); } break; default: - throw ::std::runtime_error(::format("Unexpected token in value position - ", t)); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in value position - ", t)); } - t = Token::lex_from(m_if); + t = m_lexer.get_token(); while (!m_current_composite.empty() && t.m_type == Token::Type::BraceClose) { DEBUG("Leave composite block " << m_current_block << ", " << m_current_composite); m_current_composite.pop_back(); - t = Token::lex_from(m_if); + t = m_lexer.get_token(); } if( m_current_composite.empty() ) { if(t.m_type != Token::Type::Newline && t.m_type != Token::Type::Eof) - throw ::std::runtime_error(::format("Unexpected token in TOML file after entry - ", t)); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in TOML file after entry - ", t)); } else { if( t.m_type != Token::Type::Comma ) - throw ::std::runtime_error(::format("Unexpected token in TOML file after composite entry - ", t)); + throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in TOML file after composite entry - ", t)); } return rv; } +TomlLexer::TomlLexer(const ::std::string& filename) + :m_if(filename) + ,m_filename(filename) + ,m_line(1) +{ + if( !m_if.is_open() ) { + throw ::std::runtime_error("Unable to open file '" + filename + "'"); + } +} +Token TomlLexer::get_token() +{ + auto rv = Token::lex_from(m_if); + if( rv.m_type == Token::Type::Newline ) + { + m_line ++; + } + return rv; +} +::std::ostream& operator<<(::std::ostream& os, const TomlLexer& x) +{ + os << x.m_filename << ":" << x.m_line; + return os; +} + Token Token::lex_from(::std::ifstream& is) { auto rv = Token::lex_from_inner(is); diff --git a/tools/common/toml.h b/tools/common/toml.h index 4c97e7f2..17e05142 100644 --- a/tools/common/toml.h +++ b/tools/common/toml.h @@ -15,11 +15,28 @@ class TomlFileIter; struct TomlKeyValue; -class TomlFile +struct Token; +class TomlLexer { + friend class TomlFile; /// Input file stream ::std::ifstream m_if; + ::std::string m_filename; + unsigned m_line; +protected: + TomlLexer(const ::std::string& filename); + Token get_token(); + +public: + friend ::std::ostream& operator<<(::std::ostream& os, const TomlLexer& x); +}; + +class TomlFile +{ + /// Input file stream + TomlLexer m_lexer; + /// Name of the current `[]` block ::std::vector<::std::string> m_current_block; @@ -40,6 +57,8 @@ public: // Obtain the next value in the file TomlKeyValue get_next_value(); + + const TomlLexer& lexer() const; }; struct TomlValue diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 04a9a507..5eb07104 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -31,6 +31,7 @@ extern int _putenv_s(const char*, const char*); # include <mutex> # include <condition_variable> #endif +#include <fstream> #include <climits> #include <cassert> #ifdef _WIN32 @@ -67,6 +68,9 @@ class Builder ::helpers::path m_compiler_path; size_t m_total_targets; mutable size_t m_targets_built; +#ifndef _WIN32 + mutable ::std::mutex chdir_mutex; +#endif public: Builder(const BuildOptions& opts, size_t total_targets); @@ -78,7 +82,7 @@ public: private: ::helpers::path get_crate_path(const PackageManifest& manifest, const PackageTarget& target, bool is_for_host, const char** crate_type, ::std::string* out_crate_suffix) const; bool spawn_process_mrustc(const StringList& args, StringListKV env, const ::helpers::path& logfile) const; - bool spawn_process(const char* exe_name, const StringList& args, const StringListKV& env, const ::helpers::path& logfile) const; + bool spawn_process(const char* exe_name, const StringList& args, const StringListKV& env, const ::helpers::path& logfile, const ::helpers::path& working_directory={}) const; ::helpers::path build_and_run_script(const PackageManifest& manifest, bool is_for_host) const; @@ -566,6 +570,11 @@ Builder::Builder(const BuildOptions& opts, size_t total_targets): m_total_targets(total_targets), m_targets_built(0) { + if( const char* override_path = getenv("MRUSTC_PATH") ) { + m_compiler_path = override_path; + return ; + } + // TODO: Clean this stuff up #ifdef _WIN32 char buf[1024]; size_t s = GetModuleFileName(NULL, buf, sizeof(buf)-1); @@ -1000,6 +1009,10 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& args.push_back("--crate-type"); args.push_back("bin"); args.push_back("-o"); args.push_back(outfile); args.push_back("-L"); args.push_back(this->get_output_dir(true).str()); // NOTE: Forces `is_for_host` to true here. + if( true ) + { + args.push_back("-g"); + } for(const auto& d : m_opts.lib_search_dirs) { args.push_back("-L"); @@ -1102,23 +1115,31 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& } //auto _ = ScopedChdir { manifest.directory() }; - #if _WIN32 - #else - auto fd_cwd = open(".", O_DIRECTORY); - chdir(manifest.directory().str().c_str()); - #endif - if( !this->spawn_process(script_exe_abs.str().c_str(), {}, env, out_file) ) + if( !this->spawn_process(script_exe_abs.str().c_str(), {}, env, out_file, /*working_directory=*/manifest.directory()) ) { - rename(out_file.str().c_str(), (out_file+"_failed").str().c_str()); + auto failed_filename = out_file+"_failed.txt"; + remove(failed_filename.str().c_str()); + rename(out_file.str().c_str(), failed_filename.str().c_str()); + + ::std::cerr << "Calling " << script_exe_abs << " failed" << ::std::endl; + { + ::std::ifstream ifs(failed_filename); + char linebuf[1024]; + while( ifs.good() && !ifs.eof() ) + { + ifs.getline(linebuf, sizeof(linebuf)-1); + if( strncmp(linebuf, "cargo:", 6) == 0 ) { + continue; + } + ::std::cerr << "> " << linebuf << ::std::endl; + } + } + // Build failed, return an invalid path - return ::helpers::path();; + return ::helpers::path(); } - #if _WIN32 - #else - fchdir(fd_cwd); - #endif } - + return out_file; } bool Builder::build_library(const PackageManifest& manifest, bool is_for_host, size_t index) const @@ -1154,7 +1175,7 @@ bool Builder::spawn_process_mrustc(const StringList& args, StringListKV env, con //env.push_back("MRUSTC_DEBUG", ""); return spawn_process(m_compiler_path.str().c_str(), args, env, logfile); } -bool Builder::spawn_process(const char* exe_name, const StringList& args, const StringListKV& env, const ::helpers::path& logfile) const +bool Builder::spawn_process(const char* exe_name, const StringList& args, const StringListKV& env, const ::helpers::path& logfile, const ::helpers::path& working_directory/*={}*/) const { #ifdef _WIN32 ::std::stringstream cmdline; @@ -1206,14 +1227,14 @@ bool Builder::spawn_process(const char* exe_name, const StringList& args, const WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL); } PROCESS_INFORMATION pi = { 0 }; - CreateProcessA(exe_name, (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); + CreateProcessA(exe_name, (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, (working_directory != ::helpers::path() ? working_directory.str().c_str() : NULL), &si, &pi); CloseHandle(si.hStdOutput); WaitForSingleObject(pi.hProcess, INFINITE); DWORD status = 1; GetExitCodeProcess(pi.hProcess, &status); if (status != 0) { - DEBUG("Compiler exited with non-zero exit status " << status); + DEBUG("Process exited with non-zero exit status " << status); return false; } #else @@ -1270,12 +1291,23 @@ bool Builder::spawn_process(const char* exe_name, const StringList& args, const // }); envp.push_back(nullptr); - if( posix_spawn(&pid, exe_name, &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.get_vec().data()) != 0 ) + // TODO: Acquire a lock { - ::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; + ::std::lock_guard<::std::mutex> lh { this->chdir_mutex }; + auto fd_cwd = open(".", O_DIRECTORY); + if( working_directory != ::helpers::path() ) { + chdir(working_directory.str().c_str()); + } + if( posix_spawn(&pid, exe_name, &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.get_vec().data()) != 0 ) + { + ::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; + } + if( working_directory != ::helpers::path() ) { + fchdir(fd_cwd); + } } posix_spawn_file_actions_destroy(&fa); int status = -1; diff --git a/tools/minicargo/main.cpp b/tools/minicargo/main.cpp index 7065b7f5..4e929653 100644 --- a/tools/minicargo/main.cpp +++ b/tools/minicargo/main.cpp @@ -9,9 +9,9 @@ #include <iostream> #include <cstring> // strcmp #include <map> -#include "debug.h" +#include <debug.h> #include "manifest.h" -#include "helpers.h" +#include <helpers.h> #include "repository.h" #include "build.h" diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index 8c0a7f44..edebd71a 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -317,7 +317,7 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) rv.m_targets.push_back(PackageTarget { PackageTarget::Type::Lib }); } } - // - If there's no binary section, but src/main.rs exists, add one + // - If there's no binary section, but src/main.rs exists, add as a binary if( ! ::std::any_of(rv.m_targets.begin(), rv.m_targets.end(), [](const auto& x){ return x.m_type == PackageTarget::Type::Bin; }) ) { // No library, add one pointing to lib.rs @@ -327,6 +327,10 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) rv.m_targets.push_back(PackageTarget { PackageTarget::Type::Bin }); } } + if( rv.m_targets.empty() ) + { + throw ::std::runtime_error(format("Manifest file ", path, " didn't specify any targets (and src/{main,lib}.rs doesn't exist)")); + } // Default target names for(auto& tgt : rv.m_targets) diff --git a/vsproject/build_std.cmd b/vsproject/build_std.cmd index a9d6b45d..0a360614 100644 --- a/vsproject/build_std.cmd +++ b/vsproject/build_std.cmd @@ -5,3 +5,5 @@ x64\Release\minicargo.exe ..\rustc-1.19.0-src\src\libpanic_unwind --script-overr if %errorlevel% neq 0 exit /b %errorlevel% x64\Release\minicargo.exe ..\rustc-1.19.0-src\src\libtest --script-overrides ..\script-overrides\stable-1.19.0 if %errorlevel% neq 0 exit /b %errorlevel% +x64\Release\minicargo.exe ..\lib\libproc_macro +if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/vsproject/common_lib/common_lib.vcxproj b/vsproject/common_lib/common_lib.vcxproj index 09789501..4f861999 100644 --- a/vsproject/common_lib/common_lib.vcxproj +++ b/vsproject/common_lib/common_lib.vcxproj @@ -69,7 +69,14 @@ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <PropertyGroup Label="UserMacros" /> - <PropertyGroup /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <WarningLevel>Level3</WarningLevel> diff --git a/vsproject/minicargo/minicargo.vcxproj b/vsproject/minicargo/minicargo.vcxproj index c632cee2..b62aad66 100644 --- a/vsproject/minicargo/minicargo.vcxproj +++ b/vsproject/minicargo/minicargo.vcxproj @@ -68,7 +68,14 @@ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <PropertyGroup Label="UserMacros" /> - <PropertyGroup /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <WarningLevel>Level3</WarningLevel> diff --git a/vsproject/testrunner/testrunner.vcxproj b/vsproject/testrunner/testrunner.vcxproj index 94d365f0..550614ac 100644 --- a/vsproject/testrunner/testrunner.vcxproj +++ b/vsproject/testrunner/testrunner.vcxproj @@ -68,7 +68,14 @@ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <PropertyGroup Label="UserMacros" /> - <PropertyGroup /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <WarningLevel>Level3</WarningLevel> |