aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorSimplyTheOther <simplytheother@gmail.com>2020-12-09 15:29:51 +0800
committerSimplyTheOther <simplytheother@gmail.com>2020-12-09 15:29:51 +0800
commit41c14b45ac604ebd69a6715445cdb10fc5c5ec07 (patch)
treefb9e6c7e60b9024b1857c0fcf6241c118f2f67f4 /gcc
parent815c9e8b0734d45a6e5b5a7d50f38d4af7120a8c (diff)
parentcef34bd730d80b4664d8633e2cc27a64c5cae246 (diff)
downloadgcc-41c14b45ac604ebd69a6715445cdb10fc5c5ec07.zip
gcc-41c14b45ac604ebd69a6715445cdb10fc5c5ec07.tar.gz
gcc-41c14b45ac604ebd69a6715445cdb10fc5c5ec07.tar.bz2
Merge branch 'master' of https://github.com/redbrain/gccrs
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/Make-lang.in88
-rw-r--r--gcc/rust/analysis/rust-type-resolution.cc245
-rw-r--r--gcc/rust/analysis/rust-type-resolution.h25
-rw-r--r--gcc/rust/analysis/rust-type-visitor.h261
-rw-r--r--gcc/rust/ast/rust-expr.h18
-rw-r--r--gcc/rust/ast/rust-type.h12
-rw-r--r--gcc/rust/backend/rust-compile.cc136
-rw-r--r--gcc/rust/backend/rust-compile.h3
-rw-r--r--gcc/rust/rust-backend.h5
-rw-r--r--gcc/rust/rust-session-manager.cc10
-rw-r--r--gcc/testsuite/lib/rust-dg.exp106
-rw-r--r--gcc/testsuite/lib/rust.exp213
-rw-r--r--gcc/testsuite/rust.test/compilable/arrays1.rs7
-rw-r--r--gcc/testsuite/rust.test/compilable/conditional.rs11
-rw-r--r--gcc/testsuite/rust.test/compilable/impl_block.rs14
-rw-r--r--gcc/testsuite/rust.test/compilable/static_function.rs7
-rw-r--r--gcc/testsuite/rust.test/compilable/struct_init.rs8
-rw-r--r--gcc/testsuite/rust.test/compilable/type_infer1.rs19
-rw-r--r--gcc/testsuite/rust.test/compilable/type_infer2.rs8
-rw-r--r--gcc/testsuite/rust.test/fail_compilation/arrays1.rs4
-rw-r--r--gcc/testsuite/rust.test/fail_compilation/arrays2.rs3
-rw-r--r--gcc/testsuite/rust.test/fail_compilation/bad_type1.rs3
-rw-r--r--gcc/testsuite/rust.test/fail_compilation/func1.rs9
-rw-r--r--gcc/testsuite/rust.test/rust-test.exp436
24 files changed, 1559 insertions, 92 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 35d5758..234d51b 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -1,6 +1,6 @@
# Make-lang.in -- Top level -*- makefile -*- fragment for GCC Rust frontend.
-# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+# Copyright (C) 2009-2020 Free Software Foundation, Inc.
# This file is part of GCC.
@@ -11,7 +11,7 @@
# GCC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
@@ -30,7 +30,7 @@ GCCRS_INSTALL_NAME := $(shell echo gccrs|sed '$(program_transform_name)')
GCCRS_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gccrs|sed '$(program_transform_name)')
# Define the names for selecting rust in LANGUAGES.
-rust: gccrs$(exeext) rust1$(exeext)
+rust: rust1$(exeext)
# Tell GNU make to ignore files by these names if they exist.
.PHONY: rust
@@ -54,7 +54,7 @@ gccrs$(exeext): $(GCCRS_D_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS)
$(GCCRS_D_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \
$(EXTRA_GCC_LIBS) $(LIBS)
-# List of host object files used by the rust language - files for translation from the parse tree
+# List of host object files used by the rust language - files for translation from the parse tree
# to GENERIC
# The compiler proper, not driver
GRS_OBJS = \
@@ -70,12 +70,12 @@ GRS_OBJS = \
rust/rust-ast-full-test.o \
rust/rust-session-manager.o \
rust/rust-name-resolution.o \
- rust/rust-type-resolution.o \
+ rust/rust-type-resolution.o \
rust/rust-scan.o \
rust/rust-compile.o \
rust/rust-macro-expand.o \
$(END)
-# removed object files from here
+# removed object files from here
# All language-specific object files for Rust.
RUST_ALL_OBJS = $(GRS_OBJS) $(RUST_TARGET_OBJS)
@@ -89,11 +89,15 @@ rust1$(exeext): $(RUST_ALL_OBJS) attribs.o $(BACKEND) $(LIBDEPS)
# Build hooks.
+lang_checks += check-rust
+lang_checks_parallelized += check-rust
+check_rust_parallelize = 10
+
# Copies its dependencies into the source directory. This generally should be used for generated files
-# such as Bison output files which are not version-controlled, but should be included in any release
-# tarballs. This target will be executed during a bootstrap if ‘--enable-generated-files-in-srcdir’
-# was specified as a configure option.
-rust.srcextra:
+# such as Bison output files which are not version-controlled, but should be included in any release
+# tarballs. This target will be executed during a bootstrap if ‘--enable-generated-files-in-srcdir’
+# was specified as a configure option.
+rust.srcextra:
rust.all.cross:
@@ -101,14 +105,14 @@ rust.all.cross:
rust.start.encap: gccrs$(exeext)
rust.rest.encap:
-# Build generated man pages for the front end from Texinfo manuals (see Man Page Generation), in the
-# build directory. This target is only called if the necessary tools are available, but should ignore
-# errors so as not to stop the build if errors occur; man pages are optional and the tools involved
-# may be installed in a broken way.
+# Build generated man pages for the front end from Texinfo manuals (see Man Page Generation), in the
+# build directory. This target is only called if the necessary tools are available, but should ignore
+# errors so as not to stop the build if errors occur; man pages are optional and the tools involved
+# may be installed in a broken way.
rust.man:
# Copies its dependencies into the source directory. These targets will be executed during a bootstrap
-# if ‘--enable-generated-files-in-srcdir’ was specified as a configure option.
+# if ‘--enable-generated-files-in-srcdir’ was specified as a configure option.
rust.srcman:
# Clean hooks.
@@ -119,7 +123,7 @@ rust.mostlyclean:
rust.clean: rust.mostlyclean
# Builds an etags TAGS file in the language subdirectory in the source tree.
-# TODO: add more directories if I add more
+# TODO: add more directories if I add more
rust.tags: force
cd $(srcdir)/rust; \
etags -o TAGS.sub *.y *.l *.cc *.h ast/*.h ast/*.cc lex/*.h lex/*.cc parse/*.h parse/*.cc; \
@@ -127,32 +131,32 @@ rust.tags: force
# Build documentation hooks.
-# Build info documentation for the front end, in the build directory. This target is only called by
-# ‘make bootstrap’ if a suitable version of makeinfo is available, so does not need to check for this,
-# and should fail if an error occurs.
-rust.info:
+# Build info documentation for the front end, in the build directory. This target is only called by
+# ‘make bootstrap’ if a suitable version of makeinfo is available, so does not need to check for this,
+# and should fail if an error occurs.
+rust.info:
-rust.srcinfo:
+rust.srcinfo:
-# Build DVI documentation for the front end, in the build directory. This should be done using
-# $(TEXI2DVI), with appropriate -I arguments pointing to directories of included files.
-rust.dvi:
+# Build DVI documentation for the front end, in the build directory. This should be done using
+# $(TEXI2DVI), with appropriate -I arguments pointing to directories of included files.
+rust.dvi:
-# Build PDF documentation for the front end, in the build directory. This should be done using
-# $(TEXI2PDF), with appropriate -I arguments pointing to directories of included files.
-rust.pdf:
+# Build PDF documentation for the front end, in the build directory. This should be done using
+# $(TEXI2PDF), with appropriate -I arguments pointing to directories of included files.
+rust.pdf:
-doc/rust.info:
-doc/rust.dvi:
-doc/rust.pdf:
+doc/rust.info:
+doc/rust.dvi:
+doc/rust.pdf:
-# Build HTML documentation for the front end, in the build directory.
-rust.html:
+# Build HTML documentation for the front end, in the build directory.
+rust.html:
# Install hooks.
-# Install everything that is part of the front end, apart from the compiler executables listed in
-# compilers in config-lang.in.
+# Install everything that is part of the front end, apart from the compiler executables listed in
+# compilers in config-lang.in.
rust.install-common: installdirs
# -rm -f $(DESTDIR)$(bindir)/$(GCCRS_INSTALL_NAME)$(exeext)
# -rm -f $(DESTDIR)$(bindir)/$(GCCRS_TARGET_INSTALL_NAME)$(exeext)
@@ -169,11 +173,11 @@ rust.install-common: installdirs
( cd $(DESTDIR)$(bindir) && \
$(LN) $(GCCRS_INSTALL_NAME)$(exeext) $(GCCRS_TARGET_INSTALL_NAME)$(exeext) ); \
-# Install headers needed for plugins.
+# Install headers needed for plugins.
rust.install-plugin:
-# Uninstall files installed by installing the compiler. This is currently documented not to be
-# supported, so the hook need not do anything.
+# Uninstall files installed by installing the compiler. This is currently documented not to be
+# supported, so the hook need not do anything.
rust.uninstall:
# -rm -rf $(DESTDIR)/$(bindir)/$(GCCRS_INSTALL_NAME)$(exeext)
-rm -f gccrs$(exeext) grs1$(exeext)
@@ -183,13 +187,13 @@ rust.uninstall:
# No rust-specific selftests
selftest-rust:
-# Install info documentation for the front end, if it is present in the source directory. This target
-# should have dependencies on info files that should be installed.
-rust.install-info:
+# Install info documentation for the front end, if it is present in the source directory. This target
+# should have dependencies on info files that should be installed.
+rust.install-info:
-rust.install-pdf:
+rust.install-pdf:
-# Install man pages for the front end. This target should ignore errors.
+# Install man pages for the front end. This target should ignore errors.
rust.install-man:
# Stage hooks:
diff --git a/gcc/rust/analysis/rust-type-resolution.cc b/gcc/rust/analysis/rust-type-resolution.cc
index 3e2db7f..f1edec8 100644
--- a/gcc/rust/analysis/rust-type-resolution.cc
+++ b/gcc/rust/analysis/rust-type-resolution.cc
@@ -1,5 +1,6 @@
#include "rust-type-resolution.h"
#include "rust-diagnostics.h"
+#include "rust-type-visitor.h"
#define ADD_BUILTIN_TYPE(_X, _S) \
do \
@@ -104,7 +105,13 @@ TypeResolution::typesAreCompatible (AST::Type *lhs, AST::Type *rhs,
}
AST::Type *val = NULL;
- return scope.LookupType (lhsTypeStr, &val);
+ if (!scope.LookupType (lhsTypeStr, &val))
+ {
+ rust_error_at (locus, "Unknown type: %s", lhsTypeStr.c_str ());
+ return false;
+ }
+
+ return true;
}
bool
@@ -395,19 +402,133 @@ TypeResolution::visit (AST::CompoundAssignmentExpr &expr)
void
TypeResolution::visit (AST::GroupedExpr &expr)
{}
-// void TypeResolution::visit(ArrayElems& elems) {}
+
void
TypeResolution::visit (AST::ArrayElemsValues &elems)
-{}
+{
+ // we need to generate the AST::ArrayType for this array init_expression
+ // we can get the size via get_num_values() but we need to ensure each element
+ // are type compatible
+
+ bool failed = false;
+ AST::Type *last_inferred_type = nullptr;
+ elems.iterate ([&] (AST::Expr *expr) mutable -> bool {
+ size_t before;
+ before = typeBuffer.size ();
+ expr->accept_vis (*this);
+ if (typeBuffer.size () <= before)
+ {
+ rust_error_at (expr->get_locus_slow (),
+ "unable to determine element type");
+ return false;
+ }
+
+ AST::Type *inferedType = typeBuffer.back ();
+ typeBuffer.pop_back ();
+
+ if (last_inferred_type == nullptr)
+ last_inferred_type = inferedType;
+ else
+ {
+ if (!typesAreCompatible (last_inferred_type, inferedType,
+ expr->get_locus_slow ()))
+ {
+ failed = true;
+ return false;
+ }
+ }
+
+ return true;
+ });
+
+ // nothing to do when its failed
+ if (failed)
+ return;
+
+ // FIXME This will leak
+ auto capacity
+ = new AST::LiteralExpr (std::to_string (elems.get_num_values ()),
+ AST::Literal::INT,
+ Linemap::predeclared_location ());
+ auto arrayType = new AST::ArrayType (last_inferred_type->clone_type (),
+ std::unique_ptr<AST::Expr> (capacity),
+ Linemap::predeclared_location ());
+ typeBuffer.push_back (arrayType);
+}
+
void
TypeResolution::visit (AST::ArrayElemsCopied &elems)
-{}
+{
+ printf ("ArrayElemsCopied: %s\n", elems.as_string ().c_str ());
+}
+
void
TypeResolution::visit (AST::ArrayExpr &expr)
-{}
+{
+ auto& elements = expr.get_array_elems ();
+
+ auto before = typeBuffer.size ();
+ elements->accept_vis (*this);
+ if (typeBuffer.size () <= before)
+ {
+ rust_error_at (expr.get_locus_slow (),
+ "unable to determine type for ArrayExpr");
+ return;
+ }
+
+ expr.set_inferred_type (typeBuffer.back ());
+}
+
void
TypeResolution::visit (AST::ArrayIndexExpr &expr)
-{}
+{
+ auto before = typeBuffer.size ();
+ expr.get_array_expr ()->accept_vis (*this);
+ if (typeBuffer.size () <= before)
+ {
+ rust_error_at (expr.get_locus_slow (),
+ "unable to determine type for array index expression");
+ return;
+ }
+ AST::Type *array_expr_type = typeBuffer.back ();
+ typeBuffer.pop_back ();
+
+ before = typeBuffer.size ();
+ expr.get_index_expr ()->accept_vis (*this);
+ if (typeBuffer.size () <= before)
+ {
+ rust_error_at (expr.get_index_expr ()->get_locus_slow (),
+ "unable to determine type for index expression");
+ return;
+ }
+
+ AST::Type *array_index_type = typeBuffer.back ();
+ typeBuffer.pop_back ();
+
+ // check the index_type should be an i32 which should really be
+ // more permissive
+ AST::Type *i32 = nullptr;
+ scope.LookupType ("i32", &i32);
+ rust_assert (i32 != nullptr);
+
+ if (!typesAreCompatible (array_index_type, i32,
+ expr.get_index_expr ()->get_locus_slow ()))
+ {
+ return;
+ }
+
+ // the the element type from the array_expr_type and it _must_ be an array
+ AST::ArrayType *resolved = ArrayTypeVisitor::Resolve (array_expr_type);
+ if (resolved == nullptr)
+ {
+ rust_error_at (expr.get_locus_slow (),
+ "unable to resolve type for array expression");
+ return;
+ }
+
+ typeBuffer.push_back (resolved->get_elem_type ().get ());
+}
+
void
TypeResolution::visit (AST::TupleExpr &expr)
{}
@@ -516,6 +637,10 @@ TypeResolution::visit (AST::StructExprStructFields &expr)
}
}
+ // need to correct the ordering with the respect to the struct definition and
+ // ensure we handle missing values and give them defaults
+ // FIXME
+
// setup a path in type
AST::PathIdentSegment seg (expr.get_struct_name ().as_string ());
auto typePath = ::std::unique_ptr<AST::TypePathSegment> (
@@ -649,9 +774,42 @@ TypeResolution::visit (AST::RangeFromToInclExpr &expr)
void
TypeResolution::visit (AST::RangeToInclExpr &expr)
{}
+
void
TypeResolution::visit (AST::ReturnExpr &expr)
-{}
+{
+ // Ensure the type of this matches the function
+ auto before = typeBuffer.size ();
+ expr.get_returned_expr ()->accept_vis (*this);
+
+ if (typeBuffer.size () <= before)
+ {
+ rust_error_at (expr.get_returned_expr ()->get_locus_slow (),
+ "unable to determine type for return expr");
+ return;
+ }
+
+ auto inferedType = typeBuffer.back ();
+ typeBuffer.pop_back ();
+
+ // check this is compatible with the return type
+ // this will again have issues with structs before we move to HIR
+
+ auto function = scope.CurrentFunction ();
+ if (!function->has_return_type ())
+ {
+ rust_error_at (expr.get_locus (), "return for void function %s",
+ function->as_string ().c_str ());
+ return;
+ }
+
+ if (!typesAreCompatible (function->get_return_type ().get (), inferedType,
+ expr.get_locus_slow ()))
+ {
+ return;
+ }
+}
+
void
TypeResolution::visit (AST::UnsafeBlockExpr &expr)
{}
@@ -764,18 +922,26 @@ TypeResolution::visit (AST::Function &function)
// its a marker for a void function
scope.InsertType (function.get_function_name (), function.get_return_type ().get ());
scope.InsertFunction (function.get_function_name (), &function);
+ scope.PushFunction (&function);
scope.Push ();
for (auto &param : function.get_function_params ())
{
if (!isTypeInScope (param.get_type ().get (), param.get_locus ()))
- return;
+ {
+ scope.Pop ();
+ scope.PopFunction ();
+ return;
+ }
auto before = letPatternBuffer.size ();
param.get_pattern ()->accept_vis (*this);
if (letPatternBuffer.size () <= before)
{
rust_error_at (param.get_locus (), "failed to analyse parameter name");
+
+ scope.Pop ();
+ scope.PopFunction ();
return;
}
@@ -788,7 +954,11 @@ TypeResolution::visit (AST::Function &function)
if (function.has_return_type ())
{
if (!isTypeInScope (function.get_return_type ().get (), function.get_locus ()))
- return;
+ {
+ scope.Pop ();
+ scope.PopFunction ();
+ return;
+ }
}
// walk the expression body
@@ -802,6 +972,7 @@ TypeResolution::visit (AST::Function &function)
function.locals.push_back (value);
scope.Pop ();
+ scope.PopFunction ();
}
void
@@ -1011,7 +1182,7 @@ TypeResolution::visit (AST::LetStmt &stmt)
return;
}
- AST::Type *inferedType = NULL;
+ AST::Type *inferedType = nullptr;
if (stmt.has_init_expr ())
{
auto before = typeBuffer.size ();
@@ -1044,13 +1215,51 @@ TypeResolution::visit (AST::LetStmt &stmt)
return;
}
}
- else if (stmt.has_type () && !stmt.has_init_expr ())
+ else if (stmt.has_type ())
{
- inferedType = stmt.get_type ().get ();
+ auto before = typeComparisonBuffer.size ();
+ stmt.get_type ()->accept_vis (*this);
+ if (typeComparisonBuffer.size () <= before)
+ {
+ rust_error_at (stmt.get_locus (), "failed to understand type for lhs");
+ return;
+ }
+ auto typeString = typeComparisonBuffer.back ();
+ typeComparisonBuffer.pop_back ();
+
+ // AST::Type *val = NULL;
+ // if (!scope.LookupType (typeString, &val))
+ // {
+ // rust_error_at (stmt.locus, "LetStmt has unknown type: %s",
+ // stmt.type->as_string ().c_str ());
+ // return;
+ // }
+ }
+ else if (inferedType != nullptr)
+ {
+ auto before = typeComparisonBuffer.size ();
+ inferedType->accept_vis (*this);
+ if (typeComparisonBuffer.size () <= before)
+ {
+ rust_error_at (stmt.get_locus (), "failed to understand type for lhs");
+ return;
+ }
+ auto typeString = typeComparisonBuffer.back ();
+ typeComparisonBuffer.pop_back ();
+
+ // AST::Type *val = NULL;
+ // if (!scope.LookupType (typeString, &val))
+ // {
+ // rust_error_at (stmt.get_locus (), "Inferred unknown type: %s",
+ // inferedType->as_string ().c_str ());
+ // return;
+ // }
+ }
+ else
+ {
+ rust_fatal_error (stmt.get_locus (), "Failed to determine any type for LetStmt");
+ return;
}
-
- // TODO check we know what the type is in the scope requires the builtins to
- // be defined at the constructor
// ensure the decl has the type set for compilation later on
if (!stmt.has_type ())
@@ -1118,9 +1327,13 @@ TypeResolution::visit (AST::RawPointerType &type)
void
TypeResolution::visit (AST::ReferenceType &type)
{}
+
void
TypeResolution::visit (AST::ArrayType &type)
-{}
+{
+ typeComparisonBuffer.push_back (type.get_elem_type ()->as_string ());
+}
+
void
TypeResolution::visit (AST::SliceType &type)
{}
diff --git a/gcc/rust/analysis/rust-type-resolution.h b/gcc/rust/analysis/rust-type-resolution.h
index 0c6413b..2f61a39 100644
--- a/gcc/rust/analysis/rust-type-resolution.h
+++ b/gcc/rust/analysis/rust-type-resolution.h
@@ -1,3 +1,20 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
#pragma once
#include "rust-resolution.h"
@@ -38,6 +55,12 @@ public:
return functionScope.Lookup (ident, fn);
}
+ void PushFunction (AST::Function *fn) { functionStack.push_back (fn); }
+
+ void PopFunction () { functionStack.pop_back (); }
+
+ AST::Function *CurrentFunction () { return functionStack.back (); }
+
void InsertLocal (std::string ident, AST::LetStmt *let)
{
localsPerBlock.Insert (ident, let);
@@ -74,6 +97,8 @@ public:
}
private:
+ std::vector<AST::Function *> functionStack;
+
Scope<AST::Function *> functionScope;
Scope<AST::LetStmt *> localsPerBlock;
Scope<AST::StructStruct *> structsPerBlock;
diff --git a/gcc/rust/analysis/rust-type-visitor.h b/gcc/rust/analysis/rust-type-visitor.h
new file mode 100644
index 0000000..8cfe156
--- /dev/null
+++ b/gcc/rust/analysis/rust-type-visitor.h
@@ -0,0 +1,261 @@
+// rust-type-visitor.h -- Rust AST Visitor to AST::Type specific
+// Copyright (C) 2020 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_TYPE_VISITOR_H
+#define RUST_TYPE_VISITOR_H
+
+#include "rust-system.h"
+#include "rust-ast-full.h"
+#include "rust-ast-visitor.h"
+#include "rust-scan.h"
+
+namespace Rust {
+namespace Analysis {
+
+class BaseTypeVisitor : public AST::ASTVisitor
+{
+public:
+ // visitor impl
+ // rust-ast.h
+ // virtual void visit(AttrInput& attr_input);
+ // virtual void visit(TokenTree& token_tree);
+ // virtual void visit(MacroMatch& macro_match);
+ virtual void visit (AST::Token &tok) override {}
+ virtual void visit (AST::DelimTokenTree &delim_tok_tree) override {}
+ virtual void visit (AST::AttrInputMetaItemContainer &input) override {}
+ // virtual void visit(MetaItem& meta_item) override {}
+ // void vsit(Stmt& stmt) override {}
+ // virtual void visit(Expr& expr) override {}
+ virtual void visit (AST::IdentifierExpr &ident_expr) override {}
+ // virtual void visit(Pattern& pattern) override {}
+ // virtual void visit(Type& type) override {}
+ // virtual void visit(TypeParamBound& type_param_bound) override {}
+ virtual void visit (AST::Lifetime &lifetime) override {}
+ // virtual void visit(GenericParam& generic_param) override {}
+ virtual void visit (AST::LifetimeParam &lifetime_param) override {}
+ // virtual void visit(TraitItem& trait_item) override {}
+ // virtual void visit(InherentImplItem& inherent_impl_item) override {}
+ // virtual void visit(TraitImplItem& trait_impl_item) override {}
+ virtual void visit (AST::MacroInvocationSemi &macro) override {}
+
+ // rust-path.h
+ virtual void visit (AST::PathInExpression &path) override {}
+ virtual void visit (AST::TypePathSegment &segment) override {}
+ virtual void visit (AST::TypePathSegmentGeneric &segment) override {}
+ virtual void visit (AST::TypePathSegmentFunction &segment) override {}
+ virtual void visit (AST::TypePath &path) override {}
+ virtual void visit (AST::QualifiedPathInExpression &path) override {}
+ virtual void visit (AST::QualifiedPathInType &path) override {}
+
+ // rust-expr.h
+ virtual void visit (AST::LiteralExpr &expr) override {}
+ virtual void visit (AST::AttrInputLiteral &attr_input) override {}
+ virtual void visit (AST::MetaItemLitExpr &meta_item) override {}
+ virtual void visit (AST::MetaItemPathLit &meta_item) override {}
+ virtual void visit (AST::BorrowExpr &expr) override {}
+ virtual void visit (AST::DereferenceExpr &expr) override {}
+ virtual void visit (AST::ErrorPropagationExpr &expr) override {}
+ virtual void visit (AST::NegationExpr &expr) override {}
+ virtual void visit (AST::ArithmeticOrLogicalExpr &expr) override {}
+ virtual void visit (AST::ComparisonExpr &expr) override {}
+ virtual void visit (AST::LazyBooleanExpr &expr) override {}
+ virtual void visit (AST::TypeCastExpr &expr) override {}
+ virtual void visit (AST::AssignmentExpr &expr) override {}
+ virtual void visit (AST::CompoundAssignmentExpr &expr) override {}
+ virtual void visit (AST::GroupedExpr &expr) override {}
+ // virtual void visit(ArrayElems& elems) override {}
+ virtual void visit (AST::ArrayElemsValues &elems) override {}
+ virtual void visit (AST::ArrayElemsCopied &elems) override {}
+ virtual void visit (AST::ArrayExpr &expr) override {}
+ virtual void visit (AST::ArrayIndexExpr &expr) override {}
+ virtual void visit (AST::TupleExpr &expr) override {}
+ virtual void visit (AST::TupleIndexExpr &expr) override {}
+ virtual void visit (AST::StructExprStruct &expr) override {}
+ // virtual void visit(StructExprField& field) override {}
+ virtual void visit (AST::StructExprFieldIdentifier &field) override {}
+ virtual void visit (AST::StructExprFieldIdentifierValue &field) override {}
+ virtual void visit (AST::StructExprFieldIndexValue &field) override {}
+ virtual void visit (AST::StructExprStructFields &expr) override {}
+ virtual void visit (AST::StructExprStructBase &expr) override {}
+ virtual void visit (AST::StructExprTuple &expr) override {}
+ virtual void visit (AST::StructExprUnit &expr) override {}
+ // virtual void visit(EnumExprField& field) override {}
+ virtual void visit (AST::EnumExprFieldIdentifier &field) override {}
+ virtual void visit (AST::EnumExprFieldIdentifierValue &field) override {}
+ virtual void visit (AST::EnumExprFieldIndexValue &field) override {}
+ virtual void visit (AST::EnumExprStruct &expr) override {}
+ virtual void visit (AST::EnumExprTuple &expr) override {}
+ virtual void visit (AST::EnumExprFieldless &expr) override {}
+ virtual void visit (AST::CallExpr &expr) override {}
+ virtual void visit (AST::MethodCallExpr &expr) override {}
+ virtual void visit (AST::FieldAccessExpr &expr) override {}
+ virtual void visit (AST::ClosureExprInner &expr) override {}
+ virtual void visit (AST::BlockExpr &expr) override {}
+ virtual void visit (AST::ClosureExprInnerTyped &expr) override {}
+ virtual void visit (AST::ContinueExpr &expr) override {}
+ virtual void visit (AST::BreakExpr &expr) override {}
+ virtual void visit (AST::RangeFromToExpr &expr) override {}
+ virtual void visit (AST::RangeFromExpr &expr) override {}
+ virtual void visit (AST::RangeToExpr &expr) override {}
+ virtual void visit (AST::RangeFullExpr &expr) override {}
+ virtual void visit (AST::RangeFromToInclExpr &expr) override {}
+ virtual void visit (AST::RangeToInclExpr &expr) override {}
+ virtual void visit (AST::ReturnExpr &expr) override {}
+ virtual void visit (AST::UnsafeBlockExpr &expr) override {}
+ virtual void visit (AST::LoopExpr &expr) override {}
+ virtual void visit (AST::WhileLoopExpr &expr) override {}
+ virtual void visit (AST::WhileLetLoopExpr &expr) override {}
+ virtual void visit (AST::ForLoopExpr &expr) override {}
+ virtual void visit (AST::IfExpr &expr) override {}
+ virtual void visit (AST::IfExprConseqElse &expr) override {}
+ virtual void visit (AST::IfExprConseqIf &expr) override {}
+ virtual void visit (AST::IfExprConseqIfLet &expr) override {}
+ virtual void visit (AST::IfLetExpr &expr) override {}
+ virtual void visit (AST::IfLetExprConseqElse &expr) override {}
+ virtual void visit (AST::IfLetExprConseqIf &expr) override {}
+ virtual void visit (AST::IfLetExprConseqIfLet &expr) override {}
+ // virtual void visit(MatchCase& match_case) override {}
+ // virtual void visit (AST::MatchCaseBlockExpr &match_case) override {}
+ // virtual void visit (AST::MatchCaseExpr &match_case) override {}
+ virtual void visit (AST::MatchExpr &expr) override {}
+ virtual void visit (AST::AwaitExpr &expr) override {}
+ virtual void visit (AST::AsyncBlockExpr &expr) override {}
+
+ // rust-item.h
+ virtual void visit (AST::TypeParam &param) override {}
+ // virtual void visit(WhereClauseItem& item) override {}
+ virtual void visit (AST::LifetimeWhereClauseItem &item) override {}
+ virtual void visit (AST::TypeBoundWhereClauseItem &item) override {}
+ virtual void visit (AST::Method &method) override {}
+ virtual void visit (AST::ModuleBodied &module) override {}
+ virtual void visit (AST::ModuleNoBody &module) override {}
+ virtual void visit (AST::ExternCrate &crate) override {}
+ // virtual void visit(UseTree& use_tree) override {}
+ virtual void visit (AST::UseTreeGlob &use_tree) override {}
+ virtual void visit (AST::UseTreeList &use_tree) override {}
+ virtual void visit (AST::UseTreeRebind &use_tree) override {}
+ virtual void visit (AST::UseDeclaration &use_decl) override {}
+ virtual void visit (AST::Function &function) override {}
+ virtual void visit (AST::TypeAlias &type_alias) override {}
+ virtual void visit (AST::StructStruct &struct_item) override {}
+ virtual void visit (AST::TupleStruct &tuple_struct) override {}
+ virtual void visit (AST::EnumItem &item) override {}
+ virtual void visit (AST::EnumItemTuple &item) override {}
+ virtual void visit (AST::EnumItemStruct &item) override {}
+ virtual void visit (AST::EnumItemDiscriminant &item) override {}
+ virtual void visit (AST::Enum &enum_item) override {}
+ virtual void visit (AST::Union &union_item) override {}
+ virtual void visit (AST::ConstantItem &const_item) override {}
+ virtual void visit (AST::StaticItem &static_item) override {}
+ virtual void visit (AST::TraitItemFunc &item) override {}
+ virtual void visit (AST::TraitItemMethod &item) override {}
+ virtual void visit (AST::TraitItemConst &item) override {}
+ virtual void visit (AST::TraitItemType &item) override {}
+ virtual void visit (AST::Trait &trait) override {}
+ virtual void visit (AST::InherentImpl &impl) override {}
+ virtual void visit (AST::TraitImpl &impl) override {}
+ // virtual void visit(ExternalItem& item) override {}
+ virtual void visit (AST::ExternalStaticItem &item) override {}
+ virtual void visit (AST::ExternalFunctionItem &item) override {}
+ virtual void visit (AST::ExternBlock &block) override {}
+
+ // rust-macro.h
+ virtual void visit (AST::MacroMatchFragment &match) override {}
+ virtual void visit (AST::MacroMatchRepetition &match) override {}
+ virtual void visit (AST::MacroMatcher &matcher) override {}
+ virtual void visit (AST::MacroRulesDefinition &rules_def) override {}
+ virtual void visit (AST::MacroInvocation &macro_invoc) override {}
+ virtual void visit (AST::MetaItemPath &meta_item) override {}
+ virtual void visit (AST::MetaItemSeq &meta_item) override {}
+ virtual void visit (AST::MetaWord &meta_item) override {}
+ virtual void visit (AST::MetaNameValueStr &meta_item) override {}
+ virtual void visit (AST::MetaListPaths &meta_item) override {}
+ virtual void visit (AST::MetaListNameValueStr &meta_item) override {}
+
+ // rust-pattern.h
+ virtual void visit (AST::LiteralPattern &pattern) override {}
+ virtual void visit (AST::IdentifierPattern &pattern) override {}
+ virtual void visit (AST::WildcardPattern &pattern) override {}
+ // virtual void visit(RangePatternBound& bound) override {}
+ virtual void visit (AST::RangePatternBoundLiteral &bound) override {}
+ virtual void visit (AST::RangePatternBoundPath &bound) override {}
+ virtual void visit (AST::RangePatternBoundQualPath &bound) override {}
+ virtual void visit (AST::RangePattern &pattern) override {}
+ virtual void visit (AST::ReferencePattern &pattern) override {}
+ // virtual void visit(StructPatternField& field) override {}
+ virtual void visit (AST::StructPatternFieldTuplePat &field) override {}
+ virtual void visit (AST::StructPatternFieldIdentPat &field) override {}
+ virtual void visit (AST::StructPatternFieldIdent &field) override {}
+ virtual void visit (AST::StructPattern &pattern) override {}
+ // virtual void visit(TupleStructItems& tuple_items) override {}
+ virtual void visit (AST::TupleStructItemsNoRange &tuple_items) override {}
+ virtual void visit (AST::TupleStructItemsRange &tuple_items) override {}
+ virtual void visit (AST::TupleStructPattern &pattern) override {}
+ // virtual void visit(TuplePatternItems& tuple_items) override {}
+ virtual void visit (AST::TuplePatternItemsMultiple &tuple_items) override {}
+ virtual void visit (AST::TuplePatternItemsRanged &tuple_items) override {}
+ virtual void visit (AST::TuplePattern &pattern) override {}
+ virtual void visit (AST::GroupedPattern &pattern) override {}
+ virtual void visit (AST::SlicePattern &pattern) override {}
+
+ // rust-stmt.h
+ virtual void visit (AST::EmptyStmt &stmt) override {}
+ virtual void visit (AST::LetStmt &stmt) override {}
+ virtual void visit (AST::ExprStmtWithoutBlock &stmt) override {}
+ virtual void visit (AST::ExprStmtWithBlock &stmt) override {}
+
+ // rust-type.h
+ virtual void visit (AST::TraitBound &bound) override {}
+ virtual void visit (AST::ImplTraitType &type) override {}
+ virtual void visit (AST::TraitObjectType &type) override {}
+ virtual void visit (AST::ParenthesisedType &type) override {}
+ virtual void visit (AST::ImplTraitTypeOneBound &type) override {}
+ virtual void visit (AST::TraitObjectTypeOneBound &type) override {}
+ virtual void visit (AST::TupleType &type) override {}
+ virtual void visit (AST::NeverType &type) override {}
+ virtual void visit (AST::RawPointerType &type) override {}
+ virtual void visit (AST::ReferenceType &type) override {}
+ virtual void visit (AST::ArrayType &type) override {}
+ virtual void visit (AST::SliceType &type) override {}
+ virtual void visit (AST::InferredType &type) override {}
+ virtual void visit (AST::BareFunctionType &type) override {}
+};
+
+class ArrayTypeVisitor : public BaseTypeVisitor
+{
+public:
+ static AST::ArrayType *Resolve (AST::Type *type)
+ {
+ ArrayTypeVisitor vis;
+ type->accept_vis (vis);
+ return vis.resolved;
+ }
+
+ virtual void visit (AST::ArrayType &type) override { resolved = &type; };
+
+private:
+ ArrayTypeVisitor () : resolved (nullptr) {}
+
+ AST::ArrayType *resolved;
+};
+
+} // namespace Analysis
+} // namespace Rust
+
+#endif // RUST_TYPE_VISITOR_H
diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h
index 34dfc25..c7302fe 100644
--- a/gcc/rust/ast/rust-expr.h
+++ b/gcc/rust/ast/rust-expr.h
@@ -972,6 +972,17 @@ public:
const std::vector<std::unique_ptr<Expr> > &get_values () const { return values; }
std::vector<std::unique_ptr<Expr> > &get_values () { return values; }
+ size_t get_num_values () const { return values.size (); }
+
+ void iterate (std::function<bool (Expr *)> cb)
+ {
+ for (auto it = values.begin (); it != values.end (); it++)
+ {
+ if (!cb ((*it).get ()))
+ return;
+ }
+ }
+
protected:
ArrayElemsValues *clone_array_elems_impl () const override
{
@@ -1048,6 +1059,10 @@ class ArrayExpr : public ExprWithoutBlock
// TODO: find another way to store this to save memory?
bool marked_for_strip = false;
+ // this is a reference to what the inferred type is based on
+ // this init expression
+ Type *inferredType;
+
public:
std::string as_string () const override;
@@ -1111,6 +1126,9 @@ public:
return internal_elements;
}
+ Type *get_inferred_type () { return inferredType; }
+ void set_inferred_type (Type *type) { inferredType = type; }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
diff --git a/gcc/rust/ast/rust-type.h b/gcc/rust/ast/rust-type.h
index ea9a89c..4351017 100644
--- a/gcc/rust/ast/rust-type.h
+++ b/gcc/rust/ast/rust-type.h
@@ -64,7 +64,7 @@ class ImplTraitType : public Type
{
// TypeParamBounds type_param_bounds;
// inlined form
- std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
+ std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds;
Location locus;
@@ -78,7 +78,7 @@ protected:
public:
ImplTraitType (
- std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
+ std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds,
Location locus)
: type_param_bounds (std::move (type_param_bounds)), locus (locus)
{}
@@ -124,7 +124,7 @@ class TraitObjectType : public Type
{
bool has_dyn;
// TypeParamBounds type_param_bounds;
- std::vector<std::unique_ptr<TypeParamBound>>
+ std::vector<std::unique_ptr<TypeParamBound> >
type_param_bounds; // inlined form
Location locus;
@@ -139,7 +139,7 @@ protected:
public:
TraitObjectType (
- std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
+ std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds,
Location locus, bool is_dyn_dispatch = false)
: has_dyn (is_dyn_dispatch),
type_param_bounds (std::move (type_param_bounds)), locus (locus)
@@ -330,14 +330,14 @@ class TypePath; // definition moved to "rust-path.h"
* specific order */
class TupleType : public TypeNoBounds
{
- std::vector<std::unique_ptr<Type>> elems;
+ std::vector<std::unique_ptr<Type> > elems;
Location locus;
public:
// Returns whether the tuple type is the unit type, i.e. has no elements.
bool is_unit_type () const { return elems.empty (); }
- TupleType (std::vector<std::unique_ptr<Type>> elems, Location locus)
+ TupleType (std::vector<std::unique_ptr<Type> > elems, Location locus)
: elems (std::move (elems)), locus (locus)
{}
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index 3691f9e..dd28759 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -503,19 +503,102 @@ Compilation::visit (AST::CompoundAssignmentExpr &expr)
void
Compilation::visit (AST::GroupedExpr &expr)
{}
-// void Compilation::visit(ArrayElems& elems) {}
+
void
Compilation::visit (AST::ArrayElemsValues &elems)
-{}
+{
+ std::vector< ::Bexpression *> elements;
+
+ bool failed = false;
+ elems.iterate ([&] (AST::Expr *expr) mutable -> bool {
+ Bexpression *value = nullptr;
+ VISIT_POP (expr.get_locus_slow (), expr, value, exprs);
+ if (value == nullptr)
+ {
+ rust_fatal_error (expr->get_locus_slow (),
+ "failed to compile value to array initialiser");
+ return false;
+ }
+ elements.push_back (value);
+ return true;
+ });
+
+ // nothing to do when its failed
+ if (failed)
+ return;
+
+ arrayConsStack.push_back (elements);
+}
+
void
Compilation::visit (AST::ArrayElemsCopied &elems)
{}
+
void
Compilation::visit (AST::ArrayExpr &expr)
-{}
+{
+ translatedType = nullptr;
+ expr.get_inferred_type ()->accept_vis (*this);
+ if (translatedType == nullptr)
+ {
+ rust_error_at (expr.get_locus_slow (),
+ "failed to compile array type for ArrayExpr");
+ return;
+ }
+
+ ::Btype *compiledType = translatedType;
+ translatedType = nullptr;
+
+ auto before = arrayConsStack.size ();
+ expr.get_internal_elements ()->accept_vis (*this);
+ if (arrayConsStack.size () <= before)
+ {
+ rust_error_at (expr.get_locus_slow (),
+ "failed to compile the array constructor");
+ return;
+ }
+ std::vector< ::Bexpression *> initializer = arrayConsStack.back ();
+ arrayConsStack.pop_back ();
+
+ std::vector<unsigned long> indexes;
+ for (unsigned long i = 0; i < initializer.size (); ++i)
+ indexes.push_back (i);
+
+ Bexpression *cons
+ = backend->array_constructor_expression (compiledType, indexes, initializer,
+ expr.get_locus_slow ());
+ exprs.push_back (cons);
+}
+
void
Compilation::visit (AST::ArrayIndexExpr &expr)
-{}
+{
+ Bexpression *arrayExpr = nullptr;
+ VISIT_POP (expr.get_array_expr ()->get_locus_slow (), expr.get_array_expr (),
+ arrayExpr, exprs);
+ if (arrayExpr == nullptr)
+ {
+ rust_error_at (expr.get_locus_slow (),
+ "failed to compile value to array expression reference");
+ return;
+ }
+
+ Bexpression *indexExpr = nullptr;
+ VISIT_POP (expr.get_index_expr ()->get_locus_slow (), expr.get_index_expr (),
+ indexExpr, exprs);
+ if (indexExpr == nullptr)
+ {
+ rust_error_at (expr.get_locus_slow (),
+ "failed to compile value to array index expression");
+ return;
+ }
+
+ Bexpression *indexExpression
+ = backend->array_index_expression (arrayExpr, indexExpr,
+ expr.get_locus_slow ());
+ exprs.push_back (indexExpression);
+}
+
void
Compilation::visit (AST::TupleExpr &expr)
{}
@@ -533,24 +616,6 @@ Compilation::visit (AST::StructExprFieldIdentifier &field)
void
Compilation::visit (AST::StructExprFieldIdentifierValue &field)
{
- AST::StructStruct *decl = structBuffer.back ();
- size_t index = 0;
- bool found = false;
- for (auto &df : decl->get_fields ())
- {
- if (field.get_field_name ().compare (df.get_field_name ()) == 0)
- {
- found = true;
- break;
- }
- }
- if (!found)
- {
- rust_fatal_error (field.get_value ()->get_locus_slow (),
- "failed to lookup field index");
- return;
- }
-
Bexpression *value = NULL;
VISIT_POP (field.get_value ()->get_locus_slow (), field.get_value ().get (), value, exprs);
if (value == NULL)
@@ -1394,9 +1459,34 @@ Compilation::visit (AST::RawPointerType &type)
void
Compilation::visit (AST::ReferenceType &type)
{}
+
void
Compilation::visit (AST::ArrayType &type)
-{}
+{
+ Btype *elementType;
+ translatedType = nullptr;
+ type.get_element_type ()->accept_vis (*this);
+ if (translatedType == nullptr)
+ {
+ rust_error_at (type.get_locus (),
+ "Failed to compile element type for array");
+ return;
+ }
+ elementType = translatedType;
+
+ Bexpression *length = nullptr;
+ VISIT_POP (type.get_size_expr ()->get_locus_slow (), type.get_size_expr (),
+ length, exprs);
+ if (length == nullptr)
+ {
+ rust_error_at (type.get_size_expr ()->get_locus_slow (),
+ "failed to size for array type");
+ return;
+ }
+
+ translatedType = backend->array_type (elementType, length);
+}
+
void
Compilation::visit (AST::SliceType &type)
{}
diff --git a/gcc/rust/backend/rust-compile.h b/gcc/rust/backend/rust-compile.h
index ba03483..88c8318 100644
--- a/gcc/rust/backend/rust-compile.h
+++ b/gcc/rust/backend/rust-compile.h
@@ -243,7 +243,8 @@ private:
std::vector< ::Bexpression *> exprs;
std::vector< ::Bstatement *> stmts;
std::vector< ::Bvariable *> varBuffer;
- std::vector<AST::StructStruct*> structBuffer;
+ std::vector<AST::StructStruct *> structBuffer;
+ std::vector<std::vector< ::Bexpression *> > arrayConsStack;
// careful these are the vectors we pass into the GCC middle-end
std::vector< ::Btype *> type_decls;
diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h
index ccc5e47..a907fe4 100644
--- a/gcc/rust/rust-backend.h
+++ b/gcc/rust/rust-backend.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef RUST_BACKEND_H
+#define RUST_BACKEND_H
#include <gmp.h>
#include <mpfr.h>
@@ -759,3 +760,5 @@ public:
// section in the output object file.
virtual void write_export_data (const char *bytes, unsigned int size) = 0;
};
+
+#endif // RUST_BACKEND_H
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index fd50bf1..5da2764 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -279,6 +279,12 @@ Session::init ()
// derived values from hook
options.target_data.init_derived_values ();
+
+ // setup singleton linemap
+ linemap = rust_get_linemap ();
+
+ // setup backend to GCC GIMPLE
+ backend = rust_get_backend ();
}
/* Initialise default options. Actually called before handle_option, unlike init
@@ -416,12 +422,10 @@ Session::parse_file (const char *filename)
rust_fatal_error (Location (), "cannot open filename %s: %m", filename);
}
- Backend *backend = rust_get_backend ();
-
// parse file here
/* create lexer and parser - these are file-specific and so aren't instance
* variables */
- Lexer lex (filename, std::move (file_wrap), rust_get_linemap ());
+ Lexer lex (filename, std::move (file_wrap), linemap);
Parser<Lexer> parser (std::move (lex));
// generate crate from parser
diff --git a/gcc/testsuite/lib/rust-dg.exp b/gcc/testsuite/lib/rust-dg.exp
new file mode 100644
index 0000000..e7c9852
--- /dev/null
+++ b/gcc/testsuite/lib/rust-dg.exp
@@ -0,0 +1,106 @@
+# Copyright (C) 2012-2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib gcc-dg.exp
+
+# Define rust callbacks for dg.exp.
+
+proc rust-dg-test { prog do_what extra_tool_flags } {
+ upvar dg-do-what dg-do-what
+
+ # Demote link and run tests to compile-only if D runtime is missing.
+ if ![check_effective_target_d_runtime] {
+ switch $do_what {
+ link -
+ run {
+ set do_what compile
+ set dg-do-what compile
+ }
+ }
+ }
+
+ # Strip rust.test prefix off test names to avoid pathname failures in
+ # some tests.
+ set prog [dg-trim-dirname rust.test $prog]
+
+ set result \
+ [gcc-dg-test-1 rust_target_compile $prog $do_what $extra_tool_flags]
+
+ set comp_output [lindex $result 0]
+ set output_file [lindex $result 1]
+
+ return [list $comp_output $output_file]
+}
+
+proc rust-dg-prune { system text } {
+ return [gcc-dg-prune $system $text]
+}
+
+# Utility routines.
+
+#
+# Modified dg-runtest that can cycle through a list of optimization options
+# as c-torture does.
+#
+
+proc rust-dg-runtest { testcases flags default-extra-flags } {
+ global runtests
+
+ foreach test $testcases {
+ # If we're only testing specific files and this isn't one of
+ # them, skip it.
+
+ if ![runtest_file_p $runtests $test] {
+ continue
+ }
+
+ # Use TORTURE_OPTIONS to cycle through an option list.
+ if [torture-options-exist] then {
+ global torture_with_loops
+ set option_list $torture_with_loops
+ } else {
+ set option_list { "" }
+ }
+
+ set nshort [file tail [file dirname $test]]/[file tail $test]
+
+ foreach flags_t $option_list {
+ verbose "Testing $nshort, $flags $flags_t" 1
+ dg-test $test "$flags $flags_t" ${default-extra-flags}
+ }
+ }
+}
+
+#
+# rust_load -- wrapper around default rust_load to handle tests that
+# require program arguments passed to them.
+#
+
+if { [info procs rust_load] != [list] \
+ && [info procs prev_rust_load] == [list] } {
+ rename rust_load prev_rust_load
+
+ proc rust_load { program args } {
+ global RUST_EXECUTE_ARGS
+ if [info exists RUST_EXECUTE_ARGS] then {
+ set args [concat "{$RUST_EXECUTE_ARGS}"]
+ }
+ #print "Running: $program [lindex $args 0]"
+ set result [eval [list prev_rust_load $program] $args ]
+ return $result
+ }
+}
+
diff --git a/gcc/testsuite/lib/rust.exp b/gcc/testsuite/lib/rust.exp
new file mode 100644
index 0000000..541b052
--- /dev/null
+++ b/gcc/testsuite/lib/rust.exp
@@ -0,0 +1,213 @@
+# Copyright (C) 2012-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+#
+# rust support library routines
+#
+
+load_lib prune.exp
+load_lib gcc-defs.exp
+load_lib timeout.exp
+load_lib target-libpath.exp
+
+#
+# RUST_UNDER_TEST is the compiler under test.
+#
+
+set rust_compile_options ""
+
+
+#
+# rust_version -- extract and print the version number of the compiler
+#
+
+proc rust_version { } {
+ global RUST_UNDER_TEST
+
+ rust_init
+
+ # ignore any arguments after the command
+ set compiler [lindex $RUST_UNDER_TEST 0]
+
+ # verify that the compiler exists
+ if { [is_remote host] || [which $compiler] != 0 } then {
+ set tmp [remote_exec host "$compiler -v"]
+ set status [lindex $tmp 0]
+ set output [lindex $tmp 1]
+ regexp " version \[^\n\r\]*" $output version
+ if { $status == 0 && [info exists version] } then {
+ if [is_remote host] {
+ clone_output "$compiler $version\n"
+ } else {
+ clone_output "[which $compiler] $version\n"
+ }
+ } else {
+ clone_output "Couldn't determine version of $output [which $compiler]\n"
+ }
+ } else {
+ # compiler does not exist (this should have already been detected)
+ warning "$compiler does not exist"
+ }
+}
+
+#
+# rust_include_flags -- include flags for the gcc tree structure
+#
+
+proc rust_include_flags { paths } {
+ global srcdir
+ global TESTING_IN_BUILD_TREE
+
+ set flags ""
+
+ if { [is_remote host] || ![info exists TESTING_IN_BUILD_TREE] } {
+ return "${flags}"
+ }
+
+ set gccpath ${paths}
+
+ return "$flags"
+}
+
+#
+# rust_link_flags -- linker flags for the gcc tree structure
+#
+
+proc rust_link_flags { paths } {
+ global srcdir
+ global ld_library_path
+ global RUST_UNDER_TEST
+ global shlib_ext
+ global SHARED_OPTION
+
+ set gccpath ${paths}
+ set libio_dir ""
+ set flags ""
+ set ld_library_path "."
+ set shlib_ext [get_shlib_extension]
+ set SHARED_OPTION ""
+ verbose "shared lib extension: $shlib_ext"
+
+ set_ld_library_path_env_vars
+
+ return "$flags"
+}
+
+#
+# rust_init -- called at the start of each subdir of tests
+#
+
+proc rust_init { args } {
+ global subdir
+ global rust_initialized
+ global base_dir
+ global tmpdir
+ global libdir
+ global gluefile wrap_flags
+ global objdir srcdir
+ global ALWAYS_DFLAGS
+ global TOOL_EXECUTABLE TOOL_OPTIONS
+ global RUST_UNDER_TEST
+ global TESTING_IN_BUILD_TREE
+ global TEST_ALWAYS_FLAGS
+ global gcc_warning_prefix
+ global gcc_error_prefix
+
+ # We set LC_ALL and LANG to C so that we get the same error messages as expected.
+ setenv LC_ALL C
+ setenv LANG C
+
+ if ![info exists RUST_UNDER_TEST] then {
+ if [info exists TOOL_EXECUTABLE] {
+ set RUST_UNDER_TEST $TOOL_EXECUTABLE
+ } else {
+ if { [is_remote host] || ! [info exists TESTING_IN_BUILD_TREE] } {
+ set RUST_UNDER_TEST [transform gccrs]
+ } else {
+ set RUST_UNDER_TEST [findfile $base_dir/../../gccrs "$base_dir/../../gccrs -B$base_dir/../../" [findfile $base_dir/gccrs "$base_dir/gccrs -B$base_dir/" [transform gccrs]]]
+ }
+ }
+ }
+
+ if ![is_remote host] {
+ if { [which $RUST_UNDER_TEST] == 0 } then {
+ perror "RUST_UNDER_TEST ($RUST_UNDER_TEST) does not exist"
+ exit 1
+ }
+ }
+ if ![info exists tmpdir] {
+ set tmpdir "/tmp"
+ }
+
+ if [info exists gluefile] {
+ unset gluefile
+ }
+
+ rust_maybe_build_wrapper "${tmpdir}/rust-testglue.o"
+
+ set ALWAYS_RUSTFLAGS ""
+
+ # TEST_ALWAYS_FLAGS are flags that should be passed to every
+ # compilation. They are passed first to allow individual
+ # tests to override them.
+ if [info exists TEST_ALWAYS_FLAGS] {
+ lappend ALWAYS_DFLAGS "additional_flags=$TEST_ALWAYS_FLAGS"
+ }
+
+ if ![is_remote host] {
+ if [info exists TOOL_OPTIONS] {
+ lappend ALWAYS_DFLAGS "additional_flags=[rust_include_flags [get_multilibs ${TOOL_OPTIONS}] ]"
+ lappend ALWAYS_DFLAGS "ldflags=[rust_link_flags [get_multilibs ${TOOL_OPTIONS}] ]"
+ } else {
+ lappend ALWAYS_DFLAGS "additional_flags=[rust_include_flags [get_multilibs] ]"
+ lappend ALWAYS_DFLAGS "ldflags=[rust_link_flags [get_multilibs] ]"
+ }
+ }
+
+ if [info exists TOOL_OPTIONS] {
+ lappend ALWAYS_DFLAGS "additional_flags=$TOOL_OPTIONS"
+ }
+
+ verbose -log "ALWAYS_DFLAGS set to $ALWAYS_DFLAGS"
+
+ set gcc_warning_prefix "warning:"
+ set gcc_error_prefix "(fatal )?error:"
+
+ verbose "rust is initialized" 3
+}
+
+#
+# rust_target_compile -- compile a source file
+#
+
+proc rust_target_compile { source dest type options } {
+ global tmpdir
+ global gluefile wrap_flags
+ global ALWAYS_DFLAGS
+ global RUST_UNDER_TEST
+
+ if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } {
+ lappend options "libs=${gluefile}"
+ lappend options "ldflags=${wrap_flags}"
+ }
+
+ lappend options "timeout=[timeout_value]"
+ lappend options "compiler=$RUST_UNDER_TEST"
+
+ set options [concat "$ALWAYS_DFLAGS" $options]
+ set options [dg-additional-files-options $options $source]
+ return [target_compile $source $dest $type $options]
+}
diff --git a/gcc/testsuite/rust.test/compilable/arrays1.rs b/gcc/testsuite/rust.test/compilable/arrays1.rs
new file mode 100644
index 0000000..f7e66af
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/arrays1.rs
@@ -0,0 +1,7 @@
+fn main() {
+ let xs: [i32; 5] = [1, 2, 3, 4, 5];
+ let xy = [6, 7, 8];
+
+ let a = xs[0];
+ let b = xy[2];
+}
diff --git a/gcc/testsuite/rust.test/compilable/conditional.rs b/gcc/testsuite/rust.test/compilable/conditional.rs
new file mode 100644
index 0000000..2bb3a95
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/conditional.rs
@@ -0,0 +1,11 @@
+fn main() {
+ let mut x = 5;
+
+ if x == 5 {
+ x = 1;
+ } else if x == 3 {
+ x = 2;
+ } else {
+ x = 3;
+ }
+}
diff --git a/gcc/testsuite/rust.test/compilable/impl_block.rs b/gcc/testsuite/rust.test/compilable/impl_block.rs
new file mode 100644
index 0000000..51ed74b
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/impl_block.rs
@@ -0,0 +1,14 @@
+struct Foo {
+ one: i32,
+ two: i32,
+}
+
+impl Foo {
+ fn new(a: i32, b: i32) -> Foo {
+ return Foo { one: a, two: b };
+ }
+}
+
+fn main() {
+ let cake = Foo::new(3, 4);
+}
diff --git a/gcc/testsuite/rust.test/compilable/static_function.rs b/gcc/testsuite/rust.test/compilable/static_function.rs
new file mode 100644
index 0000000..7a564af
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/static_function.rs
@@ -0,0 +1,7 @@
+fn test(x: i32) -> i32 {
+ return x + 1;
+}
+
+fn main() {
+ let call_test = test(1);
+}
diff --git a/gcc/testsuite/rust.test/compilable/struct_init.rs b/gcc/testsuite/rust.test/compilable/struct_init.rs
new file mode 100644
index 0000000..6081476
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/struct_init.rs
@@ -0,0 +1,8 @@
+struct Foo {
+ one: i32,
+ two: i32,
+}
+
+fn main() {
+ let struct_test = Foo { one: 1, two: 2 };
+}
diff --git a/gcc/testsuite/rust.test/compilable/type_infer1.rs b/gcc/testsuite/rust.test/compilable/type_infer1.rs
new file mode 100644
index 0000000..bc4b09a
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/type_infer1.rs
@@ -0,0 +1,19 @@
+struct Foo {
+ one: i32,
+ two: i32,
+}
+
+fn test(x: i32) -> i32 {
+ return x + 1;
+}
+
+fn main() {
+ let logical: bool = true;
+ let an_integer = 5;
+ let mut default_integer = 7;
+
+ default_integer = 1 + an_integer;
+
+ let call_test = test(1);
+ let struct_test = Foo { one: 1, two: 2 };
+}
diff --git a/gcc/testsuite/rust.test/compilable/type_infer2.rs b/gcc/testsuite/rust.test/compilable/type_infer2.rs
new file mode 100644
index 0000000..614c67d
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/type_infer2.rs
@@ -0,0 +1,8 @@
+fn test(x: i32) -> i32 {
+ return x + 1;
+}
+
+fn main() {
+ let an_integer = 5;
+ let call_test = test(an_integer + 1);
+}
diff --git a/gcc/testsuite/rust.test/fail_compilation/arrays1.rs b/gcc/testsuite/rust.test/fail_compilation/arrays1.rs
new file mode 100644
index 0000000..797f1ca
--- /dev/null
+++ b/gcc/testsuite/rust.test/fail_compilation/arrays1.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let xs: [i32; 5] = [1, 2, 3, 4, 5];
+ let a: bool = xs[0];
+}
diff --git a/gcc/testsuite/rust.test/fail_compilation/arrays2.rs b/gcc/testsuite/rust.test/fail_compilation/arrays2.rs
new file mode 100644
index 0000000..9ecf322
--- /dev/null
+++ b/gcc/testsuite/rust.test/fail_compilation/arrays2.rs
@@ -0,0 +1,3 @@
+fn main() {
+ let array: [i32; 5] = [1, 2, 3];
+}
diff --git a/gcc/testsuite/rust.test/fail_compilation/bad_type1.rs b/gcc/testsuite/rust.test/fail_compilation/bad_type1.rs
new file mode 100644
index 0000000..83e16f3
--- /dev/null
+++ b/gcc/testsuite/rust.test/fail_compilation/bad_type1.rs
@@ -0,0 +1,3 @@
+fn main() {
+ let logical: bool = 123;
+}
diff --git a/gcc/testsuite/rust.test/fail_compilation/func1.rs b/gcc/testsuite/rust.test/fail_compilation/func1.rs
new file mode 100644
index 0000000..5578c27
--- /dev/null
+++ b/gcc/testsuite/rust.test/fail_compilation/func1.rs
@@ -0,0 +1,9 @@
+fn test(x: i32) -> bool {
+ return x + 1;
+}
+
+fn main() {
+ let an_integer = 5;
+
+ let call_test = test(1);
+}
diff --git a/gcc/testsuite/rust.test/rust-test.exp b/gcc/testsuite/rust.test/rust-test.exp
new file mode 100644
index 0000000..cc32454
--- /dev/null
+++ b/gcc/testsuite/rust.test/rust-test.exp
@@ -0,0 +1,436 @@
+# Copyright (C) 2012-2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Test using the DMD testsuite.
+# Load support procs.
+load_lib rust-dg.exp
+
+#
+# Convert DMD arguments to RUST equivalent
+#
+
+proc rust-convert-args { args } {
+ set out ""
+
+ foreach arg [split [lindex $args 0] " "] {
+ # List of switches kept in ASCII collated order.
+ if [string match "-D" $arg] {
+ lappend out "-fdoc"
+
+ } elseif { [regexp -- {^-I([\w+/-]+)} $arg pattern path] } {
+ lappend out "-I$path"
+
+ } elseif { [regexp -- {^-J([\w+/-]+)} $arg pattern path] } {
+ lappend out "-J$path"
+
+ } elseif [string match "-allinst" $arg] {
+ lappend out "-fall-instantiations"
+
+ } elseif [string match "-betterC" $arg] {
+ lappend out "-fno-druntime"
+
+ } elseif { [string match "-boundscheck" $arg]
+ || [string match "-boundscheck=on" $arg] } {
+ lappend out "-fbounds-check"
+
+ } elseif { [string match "-boundscheck=off" $arg]
+ || [string match "-noboundscheck" $arg] } {
+ lappend out "-fno-bounds-check"
+
+ } elseif [string match "-boundscheck=safeonly" $arg] {
+ lappend out "-fbounds-check=safeonly"
+
+ } elseif [string match "-c" $arg] {
+ lappend out "-c"
+
+ } elseif [string match "-d" $arg] {
+ lappend out "-Wno-deprecated"
+
+ } elseif [string match "-de" $arg] {
+ lappend out "-Wdeprecated"
+ lappend out "-Werror"
+
+ } elseif [string match "-debug" $arg] {
+ lappend out "-fdebug"
+
+ } elseif [regexp -- {^-debug=(\w+)} $arg pattern value] {
+ lappend out "-fdebug=$value"
+
+ } elseif [string match "-dip1000" $arg] {
+ lappend out "-ftransition=dip1000"
+
+ } elseif [string match "-dip25" $arg] {
+ lappend out "-ftransition=dip25"
+
+ } elseif [string match "-dw" $arg] {
+ lappend out "-Wdeprecated"
+ lappend out "-Wno-error"
+
+ } elseif [string match "-fPIC" $arg] {
+ lappend out "-fPIC"
+
+ } elseif { [string match "-g" $arg]
+ || [string match "-gc" $arg] } {
+ lappend out "-g"
+
+ } elseif [string match "-inline" $arg] {
+ lappend out "-finline-functions"
+
+ } elseif [string match "-main" $arg] {
+ lappend out "-fmain"
+
+ } elseif [regexp -- {^-mv=([\w+=./-]+)} $arg pattern value] {
+ lappend out "-fmodule-file=$value"
+
+ } elseif [string match "-O" $arg] {
+ lappend out "-O2"
+
+ } elseif [string match "-release" $arg] {
+ lappend out "-frelease"
+
+ } elseif [regexp -- {^-transition=(\w+)} $arg pattern value] {
+ lappend out "-ftransition=$value"
+
+ } elseif [string match "-unittest" $arg] {
+ lappend out "-funittest"
+
+ } elseif [string match "-verrors=spec" $arg] {
+ lappend out "-Wspeculative"
+
+ } elseif [regexp -- {^-verrors=(\d+)} $arg pattern num] {
+ lappend out "-fmax-errors=$num"
+
+ } elseif [regexp -- {^-version=(\w+)} $arg pattern value] {
+ lappend out "-fversion=$value"
+
+ } elseif [string match "-vtls" $arg] {
+ lappend out "-ftransition=tls"
+
+ } elseif [string match "-w" $arg] {
+ lappend out "-Wall"
+ lappend out "-Werror"
+
+ } elseif [string match "-wi" $arg] {
+ lappend out "-Wall"
+ lappend out "-Wno-error"
+
+ } else {
+ # print "Unhandled Argument: $arg"
+ }
+ }
+
+ return $out
+}
+
+proc rust-copy-extra { base extra } {
+ # Split base, folder/file.
+ set type [file dirname $extra]
+
+ # print "Filename: $base - $extra"
+
+ set fdin [open $base/$extra r]
+ fconfigure $fdin -encoding binary
+
+ file mkdir $type
+ set fdout [open $extra w]
+ fconfigure $fdout -encoding binary
+
+ while { [gets $fdin copy_line] >= 0 } {
+ set out_line $copy_line
+ puts $fdout $out_line
+ }
+
+ close $fdin
+ close $fdout
+
+ # Remove file once test is finished.
+ upvar 2 cleanup_extra_files cleanups
+ lappend cleanups $extra
+
+ return $extra
+}
+
+#
+# Translate DMD test directives to dejagnu equivalent.
+#
+# COMPILE_SEPARATELY: Not handled.
+# EXECUTE_ARGS: Parameters to add to the execution of the test.
+# COMPILED_IMPORTS: List of modules files that are imported by the main
+# source file that should be included in compilation.
+# Currently handled the same as EXTRA_SOURCES.
+# EXTRA_SOURCES: List of extra sources to build and link along with
+# the test.
+# EXTRA_FILES: List of extra files to copy for the test runs.
+# PERMUTE_ARGS: The set of arguments to permute in multiple compiler
+# invocations. An empty set means only one permutation
+# with no arguments.
+# TEST_OUTPUT: The output expected from the compilation.
+# POST_SCRIPT: Not handled.
+# REQUIRED_ARGS: Arguments to add to the compiler command line.
+# DISABLED: Not handled.
+#
+
+proc dmd2dg { base test } {
+ global DEFAULT_DFLAGS
+ global PERMUTE_ARGS
+ global RUST_EXECUTE_ARGS
+
+ set PERMUTE_ARGS $DEFAULT_DFLAGS
+ set RUST_EXECUTE_ARGS ""
+
+ set extra_sources ""
+ set extra_files ""
+
+ # Split base, folder/file.
+ set type [file dirname $test]
+ set name [file tail $test]
+
+ print "Filename: $base - $test"
+
+ set fdin [open $base/$test r]
+ #fconfigure $fdin -encoding binary
+
+ file mkdir $type
+ set fdout [open $test w]
+ #fconfigure $fdout -encoding binary
+
+ while { [gets $fdin copy_line] >= 0 } {
+ set out_line $copy_line
+
+ if [regexp -- {COMPILE_SEPARATELY} $copy_line] {
+ # COMPILE_SEPARATELY is not handled.
+ regsub -- {COMPILE_SEPARATELY.*$} $copy_line "" out_line
+
+ } elseif [regexp -- {DISABLED} $copy_line] {
+ # DISABLED is not handled.
+ regsub -- {DISABLED.*$} $copy_line "" out_line
+
+ } elseif [regexp -- {POST_SCRIPT} $copy_line] {
+ # POST_SCRIPT is not handled
+ regsub -- {POST_SCRIPT.*$} $copy_line "" out_line
+
+ } elseif [regexp -- {PERMUTE_ARGS\s*:\s*(.*)} $copy_line match args] {
+ # PERMUTE_ARGS is handled by rust-do-test.
+ set PERMUTE_ARGS [rust-convert-args $args]
+ regsub -- {PERMUTE_ARGS.*$} $copy_line "" out_line
+
+ } elseif [regexp -- {EXECUTE_ARGS\s*:\s*(.*)} $copy_line match args] {
+ # EXECUTE_ARGS is handled by rust_load.
+ foreach arg $args {
+ lappend RUST_EXECUTE_ARGS $arg
+ }
+ regsub -- {EXECUTE_ARGS.*$} $copy_line "" out_line
+
+ } elseif [regexp -- {REQUIRED_ARGS\s*:\s*(.*)} $copy_line match args] {
+ # Convert all listed arguments to from dmd to rust-style.
+ set new_option "{ dg-additional-options \"[rust-convert-args $args]\" }"
+ regsub -- {REQUIRED_ARGS.*$} $copy_line $new_option out_line
+
+ } elseif [regexp -- {EXTRA_SOURCES\s*:\s*(.*)} $copy_line match sources] {
+ # EXTRA_SOURCES are appended to extra_sources list
+ foreach srcfile $sources {
+ lappend extra_sources $srcfile
+ }
+ regsub -- {EXTRA_SOURCES.*$} $copy_line "" out_line
+
+ } elseif [regexp -- {EXTRA_CPP_SOURCES\s*:\s*(.*)} $copy_line match sources] {
+ # EXTRA_CPP_SOURCES are appended to extra_sources list
+ foreach srcfile $sources {
+ # C++ sources are found in the extra-files directory.
+ lappend extra_sources "extra-files/$srcfile"
+ }
+ regsub -- {EXTRA_CPP_SOURCES.*$} $copy_line "" out_line
+
+ } elseif [regexp -- {EXTRA_FILES\s*:\s*(.*)} $copy_line match files] {
+ # EXTRA_FILES are appended to extra_files list
+ foreach file $files {
+ lappend extra_files $file
+ }
+ regsub -- {EXTRA_FILES.*$} $copy_line "" out_line
+
+ } elseif [regexp -- {COMPILED_IMPORTS\s*:\s*(.*)} $copy_line match sources] {
+ # COMPILED_IMPORTS are appended to extra_sources list
+ foreach import $sources {
+ lappend extra_sources $import
+ }
+ regsub -- {COMPILED_IMPORTS.*$} $copy_line "" out_line
+
+ }
+
+ puts $fdout $out_line
+ }
+
+ # Now that all extra sources and files have been collected, copy them all
+ # to the testsuite build directory.
+ if { [llength $extra_sources] > 0 } {
+ foreach srcfile $extra_sources {
+ rust-copy-extra $base "$type/$srcfile"
+ }
+ set out_line "// { dg-additional-sources \"$extra_sources\" }"
+ puts $fdout $out_line
+ }
+
+ if { [llength $extra_files] > 0 } {
+ foreach file $extra_files {
+ rust-copy-extra $base "$type/$file"
+ }
+ set out_line "// { dg-additional-files \"$extra_files\" }"
+ puts $fdout $out_line
+ }
+
+ # Add specific options for test type
+
+ # DMD's testsuite is extremely verbose, compiler messages from constructs
+ # such as pragma(msg, ...) would otherwise cause tests to fail.
+ set out_line "// { dg-prune-output .* }"
+ puts $fdout $out_line
+
+ # Compilable files are successful if an output is generated.
+ # Fail compilable are successful if an output is not generated.
+ # Runnable must compile, link, and return 0 to be successful by default.
+ switch $type {
+ runnable {
+ if ![isnative] {
+ set out_line "// { dg-final { output-exists } }"
+ puts $fdout $out_line
+ }
+ }
+
+ compilable {
+ puts $fdout "// { dg-final { output-exists } }"
+ }
+
+ fail_compilation {
+ puts $fdout "// { dg-do run { xfail *-*-* } }"
+ }
+ }
+
+ close $fdin
+ close $fdout
+
+ return $test
+}
+
+
+proc rust-permute-options { options } {
+ set result { }
+ set n [expr 1<<[llength $options]]
+ for { set i 0 } { $i<$n } { incr i } {
+ set option ""
+ for { set j 0 } { $j<[llength $options] } { incr j } {
+ if [expr $i & 1 << $j] {
+ append option [lindex $options $j]
+ append option " "
+ }
+ }
+ lappend result $option
+
+ }
+ return $result
+}
+
+
+proc rust-do-test { } {
+ global srcdir subdir
+ global dg-do-what-default
+ global verbose
+
+ # If a testcase doesn't have special options, use these.
+ global DEFAULT_DFLAGS
+ if ![info exists DEFAULT_DFLAGS] then {
+ set DEFAULT_DFLAGS "-g -O2"
+ }
+
+ # These are special options to use on testcase, and override DEFAULT_DFLAGS
+ global PERMUTE_ARGS
+
+ # Set if an extra option should be passed to link to shared druntime.
+ global SHARED_OPTION
+
+ # Additional arguments for rust_load
+ global RUST_EXECUTE_ARGS
+
+ # Initialize `dg'.
+ dg-init
+
+ # Allow blank linkes in output for all of rust.test.
+ global allow_blank_lines
+ set save_allow_blank_lines $allow_blank_lines
+ if { !$allow_blank_lines } {
+ set allow_blank_lines 2
+ }
+
+ # Create rust.test link so test names include that subdir.
+ catch { file link $subdir . }
+
+ # Main loop.
+
+ # set verbose 1
+ # set dg-final-code ""
+ # Find all tests and pass to routine.
+ foreach test [lsort [find $srcdir/$subdir *]] {
+ regexp -- "(.*)/(.+)/(.+)\.rs$" $test match base dir name ext
+ set ext "rs"
+
+ # Skip invalid test extensions
+ if { [lsearch "rs" $ext] == -1 } {
+ continue
+ }
+
+ # Convert to DG test.
+ set imports [format "-I%s/%s" $base $dir]
+ set cleanup_extra_files ""
+ # Include $subdir prefix so test names follow DejaGnu conventions.
+ set filename "$subdir/[dmd2dg $base $dir/$name.$ext]"
+
+ if { $dir == "runnable" } {
+ append PERMUTE_ARGS " $SHARED_OPTION"
+ }
+ set options [rust-permute-options [lsort -unique $PERMUTE_ARGS]]
+
+ switch $dir {
+ compilable {
+ for { set i 0 } { $i<[llength $options] } { incr i } {
+ set flags [lindex $options $i]
+ set dg-do-what-default "compile"
+ rust-dg-runtest $filename $flags $imports
+ }
+ }
+
+ fail_compilation {
+ for { set i 0 } { $i<[llength $options] } { incr i } {
+ set flags [lindex $options $i]
+ set dg-do-what-default "compile"
+ rust-dg-runtest $filename $flags $imports
+ }
+ }
+ }
+
+ # Cleanup test directory.
+ foreach srcfile $cleanup_extra_files {
+ file delete $subdir/$srcfile
+ }
+ file delete $filename
+ }
+
+ set allow_blank_lines $save_allow_blank_lines
+
+ # All done.
+ dg-finish
+}
+
+rust-do-test
+