From patchwork Tue Dec 6 10:13:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61496 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 19B13395B464 for ; Tue, 6 Dec 2022 10:11:58 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) by sourceware.org (Postfix) with ESMTPS id 02BB8395B072 for ; Tue, 6 Dec 2022 10:11:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 02BB8395B072 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wm1-x334.google.com with SMTP id n9-20020a05600c3b8900b003d0944dba41so7606268wms.4 for ; Tue, 06 Dec 2022 02:11:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=PqZMeW5ZPtonQ1ws5AuIz0aOoi5wwBmAkIDoBL0wGY8=; b=RIVaIKPoUHUErWOIP2+pI+NuD3H1sLiDXIU8CZsMBW6YgmeyfOIzp4ggCqYETMe+rF /4rZgcN8fwHTAla6UU9RaNB0Vn4nUmE5PcZoq0EKMgdh1NiS4DTUiiA16BxO4O4MJvuJ C93gb0AB3uKD4UJWHjG4ZESTllusHxRsD4sPUhK3VekVxNAKSuHUdmlN2a+FlPFzC9cF +C0IXRY9BncJWIddxEhh+309FVW+YkaadA/S3c9GZg2BMlKbk8JvJxgMRGMCD/YxUzkj yYqtDo5Ch6x93ZCiXzp5u/oeVYfDZ3E0mRYdChJtVexNwYuIQ0QaGeqhTcuZp7twRctl 4rfQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=PqZMeW5ZPtonQ1ws5AuIz0aOoi5wwBmAkIDoBL0wGY8=; b=6D3eCVANWm5AuzKYDVlmh35rG8CbLdtwKJwJ3t09PNxA24VftV+MCkrhIN07Kf7hHu i0di8rUXYUg7P4hBttmnE6zBRzj83/Ac2ISz5fYmRBAdVSZ5wGE75A1ECVkuEURsO4fa ni8dT1h1kEdYk56mksIVs7aMRJ0F0TeA/Xef3cCCc1Gv/hIdZI7h72Zww0JXDHzmv2dp 09O5fWVtkWtj2CfnKUSXui1nCk6NY4orSTu9Mlthn2dXvFGPkhY7DZnNkoAlP39FM8kt 4fjxrqjJiUeCWYGbpkW3TK7ILzavPs5lRPYDBP/9lUA6gCkkhC7Jt/kaa93Jq4qsDnno 2fXg== X-Gm-Message-State: ANoB5pmSygfhFoHO9CuPpvF1K3HigtlNyP02TF6YAMISFcJnj0x/3j98 8xq/S9vK4mZKSyKUj38cPwzd3Sw6RwJ75w0CSw== X-Google-Smtp-Source: AA0mqf73zIbDjm8Lj0uyw2JHzvbMs5E7P5qxSLZR2rWIWVmEBaD3qDDGC2i9MLNYZXTTmRTcKBK/NQ== X-Received: by 2002:a05:600c:3d10:b0:3cf:8a44:e1eb with SMTP id bh16-20020a05600c3d1000b003cf8a44e1ebmr54503216wmb.189.1670321499461; Tue, 06 Dec 2022 02:11:39 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.11.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:11:39 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, jakub@redhat.com, Tom Tromey , Mark Wielaard , =?utf-8?q?Marc_Poulhi=C3=A8s?= Subject: [PATCH Rust front-end v4 01/46] Use DW_ATE_UTF for the Rust 'char' type Date: Tue, 6 Dec 2022 11:13:33 +0100 Message-Id: <20221206101417.778807-2-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-65.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Tom Tromey The Rust 'char' type should use the DWARF DW_ATE_UTF encoding. Co-authored-by: Mark Wielaard Co-authored-by: Marc Poulhiès --- gcc/dwarf2out.cc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index e3920c898f5..0d8dd4f1767 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -5600,6 +5600,17 @@ is_fortran (const_tree decl) return is_fortran (); } +/* Return TRUE if the language is Rust. + Note, returns FALSE for dwarf_version < 5 && dwarf_strict. */ + +static inline bool +is_rust () +{ + unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language); + + return lang == DW_LANG_Rust; +} + /* Return TRUE if the language is Ada. */ static inline bool @@ -13231,7 +13242,11 @@ base_type_die (tree type, bool reverse) } if (TYPE_STRING_FLAG (type)) { - if (TYPE_UNSIGNED (type)) + if ((dwarf_version >= 4 || !dwarf_strict) + && is_rust () + && int_size_in_bytes (type) == 4) + encoding = DW_ATE_UTF; + else if (TYPE_UNSIGNED (type)) encoding = DW_ATE_unsigned_char; else encoding = DW_ATE_signed_char; @@ -25226,6 +25241,8 @@ gen_compile_unit_die (const char *filename) { if (strcmp (language_string, "GNU Go") == 0) language = DW_LANG_Go; + else if (strcmp (language_string, "GNU Rust") == 0) + language = DW_LANG_Rust; } } /* Use a degraded Fortran setting in strict DWARF2 so is_fortran works. */ From patchwork Tue Dec 6 10:13:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61497 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E6693396E079 for ; Tue, 6 Dec 2022 10:12:06 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by sourceware.org (Postfix) with ESMTPS id 9DE6B395B068 for ; Tue, 6 Dec 2022 10:11:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9DE6B395B068 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x435.google.com with SMTP id bs21so22753941wrb.4 for ; Tue, 06 Dec 2022 02:11:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=K90DFYBsbyQH+teLmfYXQDIK6Hva/Z6Kt8xoMTmxKEI=; b=IUbDDXh8g4+lm0wIeap+wElf9kSnboIjCs8RGn4r29kxAa+v/jHe/7MvQ7OL0yvNus 7uNzcaxOa2/22a79IEQQLUKWuL2n2acrF7aoR8xfHnfzyVAh0z/kE42JaE/B/PJuB07C xbc4yEZFFaEPGKWwt8Vc3xvw6wTX1c6rggdS3D7H6OIimwBpb7LQ7xaVD10xjQ4GHSX5 1mNxEgyMrag4dpHQbMraGPCcVvHJ+qxs3RuCWp6BgXXxYRStWO60YS370uQwvBpe2/Q/ HDj30XGPDonfZc3Rf4Mz9wNSrwOY2Ma+TiyP0UvaxA8mqjjqaxwVQ6dFRR6PvjyrETZq Nx/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=K90DFYBsbyQH+teLmfYXQDIK6Hva/Z6Kt8xoMTmxKEI=; b=RDzzRBd7rIG5JJn1d2YU0ytCsGi0yHLvf4lJ8YYCcb5YrnKPEF4JP2iD6AuS0uSJfL g7F4jqUCMkbv5Fb/fyNX2yR4ZQOuefgAhhjUZBSocWiusFJiOvLQ5mnlswECq2V6LpWU rcPlkixtSL9KtpmnbYA1rAYpZ9vbCbObB6foDafNr68l9In7eRqwzk6Q7Y6kkcHlDspD wfTxRWuwvnYPr2zzFwymr+AJtumeiIuo3jYGsiUrSltIGEnt48XRWW+hxdceBwpcDs2s lr8jnCC7P5ZGJyNfmDTYtezR3M9S+wcsxLRH8eMie52qOaFKh8cso+fxYv7PkIZFEvyS 7r0w== X-Gm-Message-State: ANoB5pl2uqupnxehqxMVF8ly0NroS3X68n/Wt16QZ6QRe7/pxWsOqMOK h8OlG/XycZv2jCZ7WB93XQ5FE1wL3lth1KfOEQ== X-Google-Smtp-Source: AA0mqf4fw/mHdAKk6cVFZDI6rHEmsc7lDFhNKcKY8X3OkFVYmbc7wAjk98uq+wGl7dxCsJ4tCRlTxA== X-Received: by 2002:adf:dec5:0:b0:242:3421:e11 with SMTP id i5-20020adfdec5000000b0024234210e11mr13707770wrn.245.1670321505086; Tue, 06 Dec 2022 02:11:45 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.11.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:11:44 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Philip Herron , =?utf-8?q?Marc_Poulhi=C3=A8s?= , Thomas Schwinge Subject: [PATCH Rust front-end v4 02/46] gccrs: Add necessary hooks for a Rust front-end testsuite Date: Tue, 6 Dec 2022 11:13:34 +0100 Message-Id: <20221206101417.778807-3-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-28.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This copies over code from other front-end testsuites to enable testing for the rust front-end specifically. Co-authored-by: Marc Poulhiès Co-authored-by: Thomas Schwinge --- gcc/testsuite/lib/rust-dg.exp | 49 +++++++++ gcc/testsuite/lib/rust.exp | 186 ++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 gcc/testsuite/lib/rust-dg.exp create mode 100644 gcc/testsuite/lib/rust.exp diff --git a/gcc/testsuite/lib/rust-dg.exp b/gcc/testsuite/lib/rust-dg.exp new file mode 100644 index 00000000000..a8a2ac0c8eb --- /dev/null +++ b/gcc/testsuite/lib/rust-dg.exp @@ -0,0 +1,49 @@ +# Copyright (C) 1997-2022 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 +# . + +load_lib gcc-dg.exp + +# Define rust callbacks for dg.exp. + +proc rust-dg-test { prog do_what extra_tool_flags } { + return [gcc-dg-test-1 rust_target_compile $prog $do_what $extra_tool_flags] +} + +proc rust-dg-prune { system text } { + return [gcc-dg-prune $system $text] +} + +# Utility routines. + +# +# 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}"] + } + 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 00000000000..6993c976304 --- /dev/null +++ b/gcc/testsuite/lib/rust.exp @@ -0,0 +1,186 @@ +# Copyright (C) 2012-2022 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 +# . + +# +# 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_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_RUSTFLAGS + 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_RUSTFLAGS "additional_flags=$TEST_ALWAYS_FLAGS" + } + + if ![is_remote host] { + if [info exists TOOL_OPTIONS] { + lappend ALWAYS_RUSTFLAGS "additional_flags=[rust_include_flags [get_multilibs ${TOOL_OPTIONS}] ]" + lappend ALWAYS_RUSTFLAGS "ldflags=[rust_link_flags [get_multilibs ${TOOL_OPTIONS}] ]" + } else { + lappend ALWAYS_RUSTFLAGS "additional_flags=[rust_include_flags [get_multilibs] ]" + lappend ALWAYS_RUSTFLAGS "ldflags=[rust_link_flags [get_multilibs] ]" + } + } + + if [info exists TOOL_OPTIONS] { + lappend ALWAYS_RUSTFLAGS "additional_flags=$TOOL_OPTIONS" + } + + verbose -log "ALWAYS_RUSTFLAGS set to $ALWAYS_RUSTFLAGS" + + 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_RUSTFLAGS + global RUST_UNDER_TEST + global individual_timeout + + # HACK: guard against infinite loops in the compiler + set individual_timeout 10 + + 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_RUSTFLAGS" $options] + set options [dg-additional-files-options $options $source] + + return [target_compile $source $dest $type $options] +} From patchwork Tue Dec 6 10:13:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61498 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BD8C0396E468 for ; Tue, 6 Dec 2022 10:12:08 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by sourceware.org (Postfix) with ESMTPS id 2C0CB395B421 for ; Tue, 6 Dec 2022 10:11:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2C0CB395B421 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x430.google.com with SMTP id d1so22710536wrs.12 for ; Tue, 06 Dec 2022 02:11:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=s8t7Tga+8hKOzjz6OoMX7Kspwdfvk82RZ+fgDlBONnE=; b=XZmB4MF8RewX///+VEEPDuIxu608lpfAT/Fqb0u4hEu+xlrS5AG/an6f5voMPizni7 o1JaC4ePhBBHYV6zkkcS8yZKdy7HTUT7bBegihIvcEm6lMajlBMitFlCmo8q8/CMpZHP cGBlYuAicW8v9gQD0WxxSShEbLL7qklyLfkEAYD1+VT/aosX0GAQBjM3U0EcdkT9OcuD Z3eMycbC0MXYIsJd/t4WYMFLBJMCckt72qbS1nqAQrWdi2haGjZtKchcDBXvab8zj7Yh r6/AQge7cwL0I23xQKNOEJtKTP/j1xMGoa7q43IQMWggptexuG9llaGubwV8sQZYw8n6 eZ9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=s8t7Tga+8hKOzjz6OoMX7Kspwdfvk82RZ+fgDlBONnE=; b=P+AWquSZ9uqlqIHhaLqLnv0M1HLZr4/v2e7ilNAudVLNYJpGrFo1IBCa7DIltIDeLe SoIlGNqa1Mk8QuYNVUyk9XDS5/p5M8oNkonnGjxV+War2Ir9U0F6Sck2+ACIcADUddnQ 9q6W98uNcWE70ONoF2CdtO/dm1bbVkNcsAwisL/Gfpn4J2Gy+J20E7EtKXn6ubtJs3xi vck4Ce6TtMZ5v7R9Xs6UU7eYFKBtCQe73/fPpzObb7AYaUu0ejpsJlCnTCiF7OSH8H0J edNHTHXoBNbRU3GN1YqFwxUvkRzIRQJxLcmgQSafbBqQmbJqqkFZlSe8AIha6mlyJX7V ud+Q== X-Gm-Message-State: ANoB5plZ58NX7CbPLzgvJQuf7E7YkZ7rOZWEXmcoEh7fjUn6OGopF34d Dw9Bcfd1S3aq72s/1mFxsX6HLmWwNZRsVHX8ww== X-Google-Smtp-Source: AA0mqf4b4QBSR4+0iGxIPDOpmaAdBAahQZxS94IXGbCd0/MPmY+wDxqRKLKJ2Ac3Cu0zND2w2nw71Q== X-Received: by 2002:a5d:53c4:0:b0:242:1f22:df3b with SMTP id a4-20020a5d53c4000000b002421f22df3bmr20543058wrw.679.1670321506647; Tue, 06 Dec 2022 02:11:46 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.11.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:11:46 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Philip Herron , Tom Tromey , Mark Wielaard , =?utf-8?q?Marc?= =?utf-8?q?_Poulhi=C3=A8s?= Subject: [PATCH Rust front-end v4 03/46] gccrs: Add Debug info testsuite Date: Tue, 6 Dec 2022 11:13:35 +0100 Message-Id: <20221206101417.778807-4-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-46.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This testsuite is specifically about testcases which scan the asm debug info for results. Co-authored-by: Tom Tromey Co-authored-by: Mark Wielaard Co-authored-by: Marc Poulhiès --- gcc/testsuite/rust/debug/chartype.rs | 10 ++++++ .../rust/debug/custom_link_section.rs | 13 ++++++++ gcc/testsuite/rust/debug/debug.exp | 33 +++++++++++++++++++ gcc/testsuite/rust/debug/i8u8.rs | 12 +++++++ gcc/testsuite/rust/debug/lang.rs | 6 ++++ gcc/testsuite/rust/debug/no_mangle.rs | 17 ++++++++++ gcc/testsuite/rust/debug/oldlang.rs | 6 ++++ gcc/testsuite/rust/debug/tuple.rs | 8 +++++ gcc/testsuite/rust/debug/win64-abi.rs | 11 +++++++ 9 files changed, 116 insertions(+) create mode 100644 gcc/testsuite/rust/debug/chartype.rs create mode 100644 gcc/testsuite/rust/debug/custom_link_section.rs create mode 100644 gcc/testsuite/rust/debug/debug.exp create mode 100644 gcc/testsuite/rust/debug/i8u8.rs create mode 100644 gcc/testsuite/rust/debug/lang.rs create mode 100644 gcc/testsuite/rust/debug/no_mangle.rs create mode 100644 gcc/testsuite/rust/debug/oldlang.rs create mode 100644 gcc/testsuite/rust/debug/tuple.rs create mode 100644 gcc/testsuite/rust/debug/win64-abi.rs diff --git a/gcc/testsuite/rust/debug/chartype.rs b/gcc/testsuite/rust/debug/chartype.rs new file mode 100644 index 00000000000..69e7ab0b17f --- /dev/null +++ b/gcc/testsuite/rust/debug/chartype.rs @@ -0,0 +1,10 @@ +// 'char' should use DW_ATE_UTF +fn main () { + let c = 'x'; +// { dg-do compile } +// Use -w to avoid warnings about the unused variables +// DW_ATE_UTF entered in DWARF 4. +// { dg-options "-w -gdwarf-4 -dA" } +// DW_ATE_UTF = 0x10 +// { dg-final { scan-assembler "0x10\[ \t]\[^\n\r]* DW_AT_encoding" } } */ +} diff --git a/gcc/testsuite/rust/debug/custom_link_section.rs b/gcc/testsuite/rust/debug/custom_link_section.rs new file mode 100644 index 00000000000..142f3513136 --- /dev/null +++ b/gcc/testsuite/rust/debug/custom_link_section.rs @@ -0,0 +1,13 @@ +#[link_section = ".universe"] +fn not_in_text() -> i32 { + 42 +} + +fn main() -> i32 { +// { dg-do compile } +// { dg-options "-gdwarf-5 -dA -w" } + not_in_text(); +// { dg-final { scan-assembler ".universe" } } */ + + 0 +} diff --git a/gcc/testsuite/rust/debug/debug.exp b/gcc/testsuite/rust/debug/debug.exp new file mode 100644 index 00000000000..c71b5930d90 --- /dev/null +++ b/gcc/testsuite/rust/debug/debug.exp @@ -0,0 +1,33 @@ +# Copyright (C) 2021-2022 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 +# . + +# Debugging tests. + +# Load support procs. +load_lib rust-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +set saved-dg-do-what-default ${dg-do-what-default} + +set dg-do-what-default "compile" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" "" +set dg-do-what-default ${saved-dg-do-what-default} + +# All done. +dg-finish diff --git a/gcc/testsuite/rust/debug/i8u8.rs b/gcc/testsuite/rust/debug/i8u8.rs new file mode 100644 index 00000000000..1cd21a4a8ff --- /dev/null +++ b/gcc/testsuite/rust/debug/i8u8.rs @@ -0,0 +1,12 @@ +// i8 and u8 types should not have the DWARF 'char' encoding. +fn main () { + let x : i8 = 5; + let y : u8 = 7; +// { dg-do compile } +// Use -w to avoid warnings about the unused variables +// { dg-options "-w -g -dA" } +// DW_ATE_signed_char = 6 +// { dg-final { scan-assembler-not "0x6\[ \t]\[^\n\r]* DW_AT_encoding" } } */ +// DW_ATE_unsigned_char = 8 +// { dg-final { scan-assembler-not "0x8\[ \t]\[^\n\r]* DW_AT_encoding" } } */ +} diff --git a/gcc/testsuite/rust/debug/lang.rs b/gcc/testsuite/rust/debug/lang.rs new file mode 100644 index 00000000000..12e0b587a02 --- /dev/null +++ b/gcc/testsuite/rust/debug/lang.rs @@ -0,0 +1,6 @@ +fn main () { +// { dg-do compile } +// { dg-options "-gdwarf-5 -dA" } +// DW_LANG_Rust is 0x1c +// { dg-final { scan-assembler "0x1c\[ \t]\[^\n\r]* DW_AT_language" } } */ +} diff --git a/gcc/testsuite/rust/debug/no_mangle.rs b/gcc/testsuite/rust/debug/no_mangle.rs new file mode 100644 index 00000000000..0cef40482f4 --- /dev/null +++ b/gcc/testsuite/rust/debug/no_mangle.rs @@ -0,0 +1,17 @@ +#[no_mangle] +fn do_not_mangle() -> i32 { + 0 +} + +fn please_mangle() {} + +fn main() { +// { dg-do compile } +// { dg-options "-gdwarf-5 -dA" } + let _ = do_not_mangle(); + please_mangle(); +// look for unmangled function name: +// { dg-final { scan-assembler "do_not_mangle:" } } */ +// look for legacy mangled function name: +// { dg-final { scan-assembler "13please_mangle" } } */ +} diff --git a/gcc/testsuite/rust/debug/oldlang.rs b/gcc/testsuite/rust/debug/oldlang.rs new file mode 100644 index 00000000000..648d6b78f06 --- /dev/null +++ b/gcc/testsuite/rust/debug/oldlang.rs @@ -0,0 +1,6 @@ +fn main () { +// { dg-do compile } +// { dg-options "-gstrict-dwarf -gdwarf-3 -dA" } +// Strict DWARF < 5 uses DW_LANG_C = 0x0002 +// { dg-final { scan-assembler "0x2\[ \t]\[^\n\r]* DW_AT_language" } } */ +} diff --git a/gcc/testsuite/rust/debug/tuple.rs b/gcc/testsuite/rust/debug/tuple.rs new file mode 100644 index 00000000000..e51a5ffdbb6 --- /dev/null +++ b/gcc/testsuite/rust/debug/tuple.rs @@ -0,0 +1,8 @@ +fn main () { +// { dg-do compile } +// { dg-options "-gdwarf-5 -dA -w" } + let x = (32, 32); +// Look for field __0 and __1 +// { dg-final { scan-assembler "__0" } } */ +// { dg-final { scan-assembler "__1" } } */ +} diff --git a/gcc/testsuite/rust/debug/win64-abi.rs b/gcc/testsuite/rust/debug/win64-abi.rs new file mode 100644 index 00000000000..b2b08cd5114 --- /dev/null +++ b/gcc/testsuite/rust/debug/win64-abi.rs @@ -0,0 +1,11 @@ +// { dg-do compile { target { x86_64-*-* } } } +// { dg-options "-gdwarf-5 -dA -w -O1 -m64" } +pub extern "win64" fn square(num: i32) -> i32 { + num * num +} + +fn main() { + // MS ABI dictates that the first argument is ecx instead of edi from the sysv world + // { dg-final { scan-assembler "%ecx, %ecx" } } + square(1); +} From patchwork Tue Dec 6 10:13:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61499 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 879E139960D2 for ; Tue, 6 Dec 2022 10:12:43 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x434.google.com (mail-wr1-x434.google.com [IPv6:2a00:1450:4864:20::434]) by sourceware.org (Postfix) with ESMTPS id E23D7395B06A for ; Tue, 6 Dec 2022 10:11:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E23D7395B06A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x434.google.com with SMTP id h12so22699079wrv.10 for ; Tue, 06 Dec 2022 02:11:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=nE4ZGqpkvyDEc30rDdvU6g5eTEfoRS6fWp6eg7xpMsY=; b=FKQ1aJZFttPzWBbOG5YXA8I17ZmQGCP0qUawLLbAkFAcE8/x1xEYBicRFodK3wwqvA Eq4TrM0Mh3pB37JdAPGeGq9sV1gR0XQiY9rkTpOgPcsr5rz0H2EVLaHoBOBiecJ26uqB zx2pb3TMqX0ekfpUuae5U4/3EJouWt9d5XyrLw3w7NS1+GZGAXZZ0w1gg0dtmCoPRnGu 7cPGyRWDiHNetsCghYYy8ZNew/M0hRK8FgudhxAHx6VP07B4iYT8pbreUZntqe1xfBwE KL8NEVfcI6IauQFzpUS+Gu9BG7W69VtVfHYid4Qa3deCoCrjP2qud3e61uW2vkAL429j PhnQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=nE4ZGqpkvyDEc30rDdvU6g5eTEfoRS6fWp6eg7xpMsY=; b=uinLuycTpw5Gwsjn9gt5bkvOn8NGRMUbGcyDpjQhWpfcYNuTsJ2OIspZ7c1ck1ytNL aiQtGo19BNR+gzwiocIdIfgFyKRPoKxArPb4u+Ekd2ELBds/MZi6gteouPs07E3UgaHM K462ZFENn9OllssQ58yIsIvWw4+pDrtl3shnjK3FnhNDZuoDLYHVKmHvKrQhRGHEGyl4 Es4HPitMiA/mVOL73Ijrjt8jg0ZmK1A5HVObxpaLcZ5aI23ZKu/1MfKrRWXyFKxZo7uk 2d+14gFH0cMjzLpPjLSq+IOUpRcVU0k9H+FMs+kc+JEMBUcqcspg6V0JScVkslrkCDJr 3pvQ== X-Gm-Message-State: ANoB5pm6poysY/5SvN44G+wNp/vwrIK88Sd9eqEZvRIMEPOkrceDk9wE wRfa8WZe64HY2T94oHQtPWebJMGr6zqA2daOMA== X-Google-Smtp-Source: AA0mqf7Y//C1bHDTStbCECBLk9jWPUSbNgqZiHfUSJ/rwzKVt+isI6+qJKmGYMIZmSczwyn6AjHh3w== X-Received: by 2002:a05:6000:60c:b0:242:10ac:6ab2 with SMTP id bn12-20020a056000060c00b0024210ac6ab2mr26147893wrb.552.1670321510090; Tue, 06 Dec 2022 02:11:50 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.11.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:11:49 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Philip Herron Subject: [PATCH Rust front-end v4 04/46] gccrs: Add link cases testsuite Date: Tue, 6 Dec 2022 11:13:36 +0100 Message-Id: <20221206101417.778807-5-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-42.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This testsuite is heavily inspired from the LTO testsuite that uses a pattern where each file is compiled to an object file and finally linked together. Since Rust does not have headers/prototypes, we rely on the ordering here so that all files numbered greater than zero get compiled to object files first. This leaves the _0 file free to test the 'extern crate' and 'use' keywords to force testing of the compiler to read metadata from the other 'crates'. --- gcc/testsuite/rust/link/generic_function_0.rs | 7 + gcc/testsuite/rust/link/generic_function_1.rs | 3 + gcc/testsuite/rust/link/link.exp | 172 ++++++++++++++++++ gcc/testsuite/rust/link/simple_function_0.rs | 8 + gcc/testsuite/rust/link/simple_function_1.rs | 3 + gcc/testsuite/rust/link/trait_import_0.rs | 19 ++ gcc/testsuite/rust/link/trait_import_1.rs | 6 + 7 files changed, 218 insertions(+) create mode 100644 gcc/testsuite/rust/link/generic_function_0.rs create mode 100644 gcc/testsuite/rust/link/generic_function_1.rs create mode 100644 gcc/testsuite/rust/link/link.exp create mode 100644 gcc/testsuite/rust/link/simple_function_0.rs create mode 100644 gcc/testsuite/rust/link/simple_function_1.rs create mode 100644 gcc/testsuite/rust/link/trait_import_0.rs create mode 100644 gcc/testsuite/rust/link/trait_import_1.rs diff --git a/gcc/testsuite/rust/link/generic_function_0.rs b/gcc/testsuite/rust/link/generic_function_0.rs new file mode 100644 index 00000000000..58b8eb13db6 --- /dev/null +++ b/gcc/testsuite/rust/link/generic_function_0.rs @@ -0,0 +1,7 @@ +extern crate generic_function_1; +use generic_function_1::generic_function; + +fn main() -> i32 { + let a = generic_function(123); + a - 123 +} diff --git a/gcc/testsuite/rust/link/generic_function_1.rs b/gcc/testsuite/rust/link/generic_function_1.rs new file mode 100644 index 00000000000..8fb0788e388 --- /dev/null +++ b/gcc/testsuite/rust/link/generic_function_1.rs @@ -0,0 +1,3 @@ +pub fn generic_function(a: X) -> X { + a +} diff --git a/gcc/testsuite/rust/link/link.exp b/gcc/testsuite/rust/link/link.exp new file mode 100644 index 00000000000..8b2e93ceab6 --- /dev/null +++ b/gcc/testsuite/rust/link/link.exp @@ -0,0 +1,172 @@ +# Copyright (C) 2021-2022 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 +# . + +# Execute tests, torture testing. + +# Load support procs. +load_lib rust-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +set saved-dg-do-what-default ${dg-do-what-default} + +set dg-do-what-default "assemble" + +# rs-obj -- compile to an object file +# +# SOURCE is the source file +# DEST is the object file +# OPTALL is the list of compiler options to use with all tests +# OPTFILE is the list of compiler options to use with this file +# OPTSTR is the options to print with test messages +# XFAILDATA is the xfail data to be passed to the compiler +proc rs-obj { source dest optall optfile optstr xfaildata } { + global tool + global compiler_conditional_xfail_data + + # Set up the options for compiling this file. + set options "" + lappend options "additional_flags=$optall $optfile" + + set compiler_conditional_xfail_data $xfaildata + set comp_output [${tool}_target_compile "$source" "$dest" object $options] +} + +# rs-execute -- compile multi-file tests +# +# SRC1 is the full pathname of the main file of the testcase. +# SID identifies a test suite in the names of temporary files. +proc rs-execute-1 { src1 } { + global srcdir tmpdir + + # Get extra flags for this test from the primary source file, and + # process other dg-* options that this suite supports. Warn about + # unsupported flags. + verbose "rs-execute: $src1" 1 + set compile_type "run" + set compile_xfail(0) "" + + # Set up the names of the other source files. + set dir [file dirname $src1] + set base [file rootname $src1] + set base [string range $base [string length $dir] end] + regsub "_0" $base "" base + regsub "/" $base "" base + set src_list $src1 + set i 1 + set done 0 + while { !$done } { + set names [glob -nocomplain -types f -- "${dir}/${base}_${i}.*"] + if { [llength ${names}] > 1 } { + warning "rs-link-execute: more than one file matched ${dir}/${base}_${i}.*" + } + if { [llength ${names}] == 1 } { + lappend src_list [lindex ${names} 0] + incr i + } else { + set num_srcs ${i} + set done 1 + } + } + + + # Define the names of the object files. + set obj_list "" + for {set i 0} {$i < $num_srcs} {incr i} { + lappend obj_list "${base}_${i}.o" + } + + # Get the base name of this test, for use in messages. + set testcase [lindex ${src_list} 0] + + # Remove the $srcdir and $tmpdir prefixes from $src1. (It would + # be possible to use "regsub" here, if we were careful to escape + # all regular expression characters in $srcdir and $tmpdir, but + # that would be more complicated that this approach.) + if {[string first "$srcdir/" "${testcase}"] == 0} { + set testcase [string range "${testcase}" [string length "$srcdir/"] end] + } + if {[string first "$tmpdir/" "$testcase"] == 0} { + set testcase [string range "$testcase" [string length "$tmpdir/"] end] + set testcase "tmpdir-$testcase" + } + # If we couldn't rip $srcdir out of `src1' then just do the best we can. + # The point is to reduce the unnecessary noise in the logs. Don't strip + # out too much because different testcases with the same name can confuse + # `test-tool'. + if [string match "/*" $testcase] then { + set testcase "[file tail [file dirname $src1]]/[file tail $src1]" + } + + # Set up the base name of executable files so they'll be unique. + regsub -all "\[./\]" $testcase "-" execbase + + verbose "Testing $testcase - $obj_list - $src_list" + + # There's a unique name for each executable we generate. + set execname "${execbase}-1.exe" + + # The LTO tests don't use dg-test, so testname_with_flags and + # output_file need to be defined explicitly for each file. scan-symbol + # directives rely on both of these to be defined to find the symbol to + # scan and for the text to print in the PASS/FAIL since they can also + # be called from dg-test. testname_with_flags is also used via + # testname-for-summary when calling into generic function below to + # clean temporary files. + set output_file $execname + set testname_with_flags $execname + + file_on_host delete $execname + + rs-obj [lindex ${src_list} 1] [lindex ${obj_list} 1] "" "" "" "" + rs-obj [lindex ${src_list} 0] [lindex ${obj_list} 0] "" "" "" "" + + gcc-dg-runtest [lindex ${src_list} 0] "" "" + + # FIXME it would be ideal if we could link then execute these tests. + # I was not able to figure out how to specify gc-dg-runtest to link + # against the first object. +} + +proc rs-link-execute { src1 } { + rs-execute-1 $src1 +} + +# Main loop. +foreach src [lsort [find $srcdir/$subdir *_0.rs]] { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $src] then { + continue + } + + # To prevent 'runtest_file_p' being tested again (for example, via + # 'gcc-dg-runtest'), with undesirable consequences due to its side effects, + # interpose a dummy: + rename runtest_file_p saved_runtest_file_p + proc runtest_file_p { runtests testcase } { + return 1 + } + rs-link-execute $src + rename runtest_file_p {} + rename saved_runtest_file_p runtest_file_p +} + +set dg-do-what-default ${saved-dg-do-what-default} + +# All done. +dg-finish diff --git a/gcc/testsuite/rust/link/simple_function_0.rs b/gcc/testsuite/rust/link/simple_function_0.rs new file mode 100644 index 00000000000..5bd4926def8 --- /dev/null +++ b/gcc/testsuite/rust/link/simple_function_0.rs @@ -0,0 +1,8 @@ +extern crate simple_function_1; +use simple_function_1::test_func; + +fn main() -> i32 { + let a = test_func(123); + // { dg-bogus "call to extern function" "" { xfail *-*-* } .-1 } + a - 124 +} diff --git a/gcc/testsuite/rust/link/simple_function_1.rs b/gcc/testsuite/rust/link/simple_function_1.rs new file mode 100644 index 00000000000..aaa1fc39367 --- /dev/null +++ b/gcc/testsuite/rust/link/simple_function_1.rs @@ -0,0 +1,3 @@ +pub fn test_func(a: i32) -> i32 { + a + 1 +} diff --git a/gcc/testsuite/rust/link/trait_import_0.rs b/gcc/testsuite/rust/link/trait_import_0.rs new file mode 100644 index 00000000000..ac8c5811d22 --- /dev/null +++ b/gcc/testsuite/rust/link/trait_import_0.rs @@ -0,0 +1,19 @@ +extern crate trait_import_1; +use trait_import_1::Add; + +struct Foo(i32); + +impl Add for Foo { + type Output = Foo; + + fn add(self, other: Foo) -> Foo { + Foo(self.0 + other.0) + } +} + +fn main() -> i32 { + let a; + a = Foo(1) + Foo(2); + + 0 +} diff --git a/gcc/testsuite/rust/link/trait_import_1.rs b/gcc/testsuite/rust/link/trait_import_1.rs new file mode 100644 index 00000000000..fc7f5168ede --- /dev/null +++ b/gcc/testsuite/rust/link/trait_import_1.rs @@ -0,0 +1,6 @@ +#[lang = "add"] +pub trait Add { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; +} From patchwork Tue Dec 6 10:13:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61503 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D3203396D807 for ; Tue, 6 Dec 2022 10:14:14 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by sourceware.org (Postfix) with ESMTPS id 0D1CB395BC7B for ; Tue, 6 Dec 2022 10:11:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0D1CB395BC7B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x42b.google.com with SMTP id u12so21779199wrr.11 for ; Tue, 06 Dec 2022 02:11:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=t8Euuea6PxM/xMsv8BqIpwhggzUFxXTpctQImEe2MlE=; b=PCYBEQH+WPD7Ijnr5xHwUylunGhEAXDV2sh0NL/ZCNgAOv/P0s+6CC4/KO1yYUlPye uxHFQ71o1Bd0oKnGVk2Rrnwpclylt+fke7D4UOfr2RTR4vwyOWQ5uLPyGcfhcnIGxrIf 8arew4GN2df0RfczA7aKMSBCwK323OqIvvUujd8e0Q2bwOIBoRwzFp7UHEf1eejNKJsC +febx1EeStoyOfImWzu8lHK6+Qyrb7X5Mqh2sGh5S9wNa/CNOjiR56gYHbtjXKVcNH2Q 4UGJFDcVi0lL3Fvn3w/2A/J0q6zx1q6Ciew+vz1r+jsUQGLRhe/zsXqxzBAiirBiYQ0E DYPw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=t8Euuea6PxM/xMsv8BqIpwhggzUFxXTpctQImEe2MlE=; b=N7CrwuqZu+au68RXeKMG6E3SFtmD/JoeU/7iTnhY9UiCih1YcqeO3c5hwEu55+PYxh 5h9MB6+M5mNHQSu24KS3E3GXG8XCy7eMaNhD6yv6Qe8fVowRbNa3oFUijiDxSKoAhyhD ii3XIaPlUgvoBavzhJBw9wQ1gUUfMannGtdismCttr/QmgDF0U4IEXHEPqsRd+B+p4Jg nynwl7M0h4KtSXXHRl3tHBkHDeoKVqXMSNJE/M3klB3w8im49eJ4h8byDI2Mxpd7v5tX USzu009L4RNGkU6ZPq+kU9GgzdJfNCw53dV2utcx9oFNwou486AhodocqqBWS97DXaWv VZ8g== X-Gm-Message-State: ANoB5pl08R/iJlhU+tvShTEsoH0647KV8tsQ3J3iIEvRxcOAaEtSZ4cU jlT0rsJTJbodzEKPzGCgZYh2bT3vCae2MzSKJA== X-Google-Smtp-Source: AA0mqf6SDOD9HzcFh/IgGCfbpmMo7P8y2AzVltjV5eHtF3r7/aCYD+OIAAj0qZa+cn9HMed2pNBfEQ== X-Received: by 2002:a5d:4c4c:0:b0:242:5023:9bb3 with SMTP id n12-20020a5d4c4c000000b0024250239bb3mr8001319wrt.160.1670321511925; Tue, 06 Dec 2022 02:11:51 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.11.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:11:51 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Philip Herron , Arthur Cohen , Thomas Schwinge , Mark Wielaard , =?utf-8?q?Marc_Poulhi=C3=A8s?= Subject: [PATCH Rust front-end v4 05/46] gccrs: Add general compilation test cases Date: Tue, 6 Dec 2022 11:13:37 +0100 Message-Id: <20221206101417.778807-6-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-25.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This suite of tests has two sections: compile/*.rs and compile/torture/*.rs. The first section is comprised entirely of dg-compile tests, containing a mixture of dg-warning and dg-error annotations and some with no annotations, ensuring the creation of resulting asm output. The second section is the same, but has tests which are ran with the full torture options, for coverage of test cases that may have an issue with a specific optimization level. Co-authored-by: Arthur Cohen Co-authored-by: Thomas Schwinge Co-authored-by: Mark Wielaard Co-authored-by: Marc Poulhiès --- gcc/testsuite/rust/compile/abi-options1.rs | 7 ++ gcc/testsuite/rust/compile/array3.rs | 4 + .../rust/compile/array_empty_list.rs | 4 + gcc/testsuite/rust/compile/arrays1.rs | 4 + gcc/testsuite/rust/compile/arrays2.rs | 5 + .../rust/compile/attr-mismatch-crate-name.rs | 4 + gcc/testsuite/rust/compile/attr_cold.rs | 12 +++ gcc/testsuite/rust/compile/attr_deprecated.rs | 14 +++ .../rust/compile/attr_deprecated_2.rs | 11 +++ gcc/testsuite/rust/compile/bad-crate-name.rs | 4 + gcc/testsuite/rust/compile/bad=file-name.rs | 7 ++ .../rust/compile/bad_as_bool_char.rs | 18 ++++ .../rust/compile/bad_file_name.txt.rs | 3 + gcc/testsuite/rust/compile/bad_inner_doc.rs | 15 +++ .../rust/compile/bad_pub_enumitems.rs | 47 +++++++++ gcc/testsuite/rust/compile/bad_stmt_enums.rs | 22 +++++ .../rust/compile/bad_toplevel_enums.rs | 19 ++++ gcc/testsuite/rust/compile/bad_tuple_index.rs | 66 +++++++++++++ gcc/testsuite/rust/compile/bad_type1.rs | 3 + gcc/testsuite/rust/compile/bad_type2.rs | 14 +++ gcc/testsuite/rust/compile/break1.rs | 6 ++ gcc/testsuite/rust/compile/break2.rs | 15 +++ .../compile/builtin_macro_compile_error.rs | 13 +++ .../rust/compile/builtin_macro_concat.rs | 17 ++++ .../rust/compile/builtin_macro_env.rs | 20 ++++ .../compile/builtin_macro_include_bytes.rs | 13 +++ .../rust/compile/builtin_macro_include_str.rs | 13 +++ .../rust/compile/builtin_macro_not_found.rs | 4 + gcc/testsuite/rust/compile/bytecharstring.rs | 8 ++ .../rust/compile/canonical_paths1.rs | 25 +++++ gcc/testsuite/rust/compile/cast1.rs | 5 + gcc/testsuite/rust/compile/cfg1.rs | 31 ++++++ gcc/testsuite/rust/compile/cfg2.rs | 13 +++ gcc/testsuite/rust/compile/cfg3.rs | 11 +++ gcc/testsuite/rust/compile/cfg4.rs | 11 +++ gcc/testsuite/rust/compile/cfg5.rs | 11 +++ gcc/testsuite/rust/compile/compile.exp | 35 +++++++ gcc/testsuite/rust/compile/complex-path1.rs | 18 ++++ gcc/testsuite/rust/compile/const-issue1440.rs | 76 +++++++++++++++ gcc/testsuite/rust/compile/const1.rs | 6 ++ gcc/testsuite/rust/compile/const2.rs | 7 ++ gcc/testsuite/rust/compile/const3.rs | 7 ++ .../rust/compile/const_generics_1.rs | 19 ++++ .../rust/compile/const_generics_2.rs | 4 + .../rust/compile/const_generics_3.rs | 26 +++++ .../rust/compile/const_generics_4.rs | 7 ++ .../rust/compile/const_generics_5.rs | 12 +++ .../rust/compile/const_generics_6.rs | 2 + gcc/testsuite/rust/compile/continue1.rs | 10 ++ gcc/testsuite/rust/compile/deadcode_err1.rs | 11 +++ gcc/testsuite/rust/compile/deadcode_err2.rs | 16 +++ .../rust/compile/debug-diagnostics-default.rs | 5 + .../rust/compile/debug-diagnostics-off.rs | 7 ++ .../rust/compile/debug-diagnostics-on.rs | 7 ++ .../compile/doc_isolated_cr_block_comment.rs | 3 + .../doc_isolated_cr_inner_block_comment.rs | 5 + .../doc_isolated_cr_inner_line_comment.rs | 5 + .../compile/doc_isolated_cr_line_comment.rs | 3 + gcc/testsuite/rust/compile/dup_fields.rs | 23 +++++ .../compile/empty_comment_before_match.rs | 7 ++ .../rust/compile/expected_type_args2.rs | 6 ++ .../rust/compile/expected_type_args3.rs | 8 ++ gcc/testsuite/rust/compile/func1.rs | 9 ++ gcc/testsuite/rust/compile/func2.rs | 7 ++ gcc/testsuite/rust/compile/func3.rs | 9 ++ gcc/testsuite/rust/compile/func4.rs | 6 ++ gcc/testsuite/rust/compile/func5.rs | 7 ++ .../rust/compile/generic-default1.rs | 7 ++ gcc/testsuite/rust/compile/generics1.rs | 11 +++ gcc/testsuite/rust/compile/generics10.rs | 12 +++ gcc/testsuite/rust/compile/generics11.rs | 12 +++ gcc/testsuite/rust/compile/generics12.rs | 6 ++ gcc/testsuite/rust/compile/generics13.rs | 1 + gcc/testsuite/rust/compile/generics2.rs | 11 +++ gcc/testsuite/rust/compile/generics3.rs | 10 ++ gcc/testsuite/rust/compile/generics4.rs | 16 +++ gcc/testsuite/rust/compile/generics5.rs | 10 ++ gcc/testsuite/rust/compile/generics6.rs | 31 ++++++ gcc/testsuite/rust/compile/generics7.rs | 26 +++++ gcc/testsuite/rust/compile/generics8.rs | 15 +++ gcc/testsuite/rust/compile/generics9.rs | 10 ++ .../rust/compile/implicit_returns_err1.rs | 12 +++ .../rust/compile/implicit_returns_err2.rs | 10 ++ .../rust/compile/implicit_returns_err3.rs | 9 ++ .../rust/compile/implicit_returns_err4.rs | 10 ++ .../rust/compile/infer-crate-name.rs | 7 ++ gcc/testsuite/rust/compile/inline_1.rs | 16 +++ gcc/testsuite/rust/compile/inline_2.rs | 6 ++ gcc/testsuite/rust/compile/issue-1005.rs | 4 + gcc/testsuite/rust/compile/issue-1019.rs | 19 ++++ gcc/testsuite/rust/compile/issue-1023.rs | 4 + gcc/testsuite/rust/compile/issue-1031.rs | 17 ++++ gcc/testsuite/rust/compile/issue-1034.rs | 16 +++ gcc/testsuite/rust/compile/issue-1089.rs | 6 ++ gcc/testsuite/rust/compile/issue-1128.rs | 6 ++ gcc/testsuite/rust/compile/issue-1129-1.rs | 4 + gcc/testsuite/rust/compile/issue-1129-2.rs | 22 +++++ gcc/testsuite/rust/compile/issue-1130.rs | 47 +++++++++ gcc/testsuite/rust/compile/issue-1131.rs | 4 + gcc/testsuite/rust/compile/issue-1152.rs | 8 ++ gcc/testsuite/rust/compile/issue-1165.rs | 5 + gcc/testsuite/rust/compile/issue-1173.rs | 23 +++++ gcc/testsuite/rust/compile/issue-1226.rs | 6 ++ gcc/testsuite/rust/compile/issue-1234.rs | 4 + gcc/testsuite/rust/compile/issue-1235.rs | 21 ++++ gcc/testsuite/rust/compile/issue-1237.rs | 23 +++++ gcc/testsuite/rust/compile/issue-1251.rs | 14 +++ gcc/testsuite/rust/compile/issue-1271.rs | 5 + gcc/testsuite/rust/compile/issue-1289.rs | 43 +++++++++ gcc/testsuite/rust/compile/issue-1323-1.rs | 18 ++++ gcc/testsuite/rust/compile/issue-1323-2.rs | 16 +++ gcc/testsuite/rust/compile/issue-1383.rs | 8 ++ gcc/testsuite/rust/compile/issue-1393.rs | 13 +++ gcc/testsuite/rust/compile/issue-1447.rs | 28 ++++++ gcc/testsuite/rust/compile/issue-407-2.rs | 21 ++++ gcc/testsuite/rust/compile/issue-407.rs | 9 ++ gcc/testsuite/rust/compile/issue-557.rs | 4 + gcc/testsuite/rust/compile/issue-635-1.rs | 5 + gcc/testsuite/rust/compile/issue-635-2.rs | 5 + gcc/testsuite/rust/compile/lookup_err1.rs | 7 ++ .../rust/compile/macro-issue1053-2.rs | 5 + gcc/testsuite/rust/compile/macro-issue1053.rs | 3 + gcc/testsuite/rust/compile/macro-issue1224.rs | 9 ++ gcc/testsuite/rust/compile/macro-issue1233.rs | 22 +++++ .../rust/compile/macro-issue1395-2.rs | 7 ++ gcc/testsuite/rust/compile/macro-issue1395.rs | 5 + .../rust/compile/macro-issue1400-2.rs | 32 ++++++ gcc/testsuite/rust/compile/macro-issue1400.rs | 33 +++++++ gcc/testsuite/rust/compile/macro1.rs | 3 + gcc/testsuite/rust/compile/macro10.rs | 11 +++ gcc/testsuite/rust/compile/macro11.rs | 11 +++ gcc/testsuite/rust/compile/macro12.rs | 8 ++ gcc/testsuite/rust/compile/macro13.rs | 12 +++ gcc/testsuite/rust/compile/macro14.rs | 10 ++ gcc/testsuite/rust/compile/macro15.rs | 12 +++ gcc/testsuite/rust/compile/macro16.rs | 11 +++ gcc/testsuite/rust/compile/macro17.rs | 10 ++ gcc/testsuite/rust/compile/macro18.rs | 14 +++ gcc/testsuite/rust/compile/macro19.rs | 19 ++++ gcc/testsuite/rust/compile/macro2.rs | 3 + gcc/testsuite/rust/compile/macro20.rs | 16 +++ gcc/testsuite/rust/compile/macro21.rs | 9 ++ gcc/testsuite/rust/compile/macro22.rs | 10 ++ gcc/testsuite/rust/compile/macro23.rs | 25 +++++ gcc/testsuite/rust/compile/macro25.rs | 9 ++ gcc/testsuite/rust/compile/macro26.rs | 10 ++ gcc/testsuite/rust/compile/macro27.rs | 8 ++ gcc/testsuite/rust/compile/macro28.rs | 8 ++ gcc/testsuite/rust/compile/macro29.rs | 8 ++ gcc/testsuite/rust/compile/macro3.rs | 3 + gcc/testsuite/rust/compile/macro30.rs | 8 ++ gcc/testsuite/rust/compile/macro31.rs | 8 ++ gcc/testsuite/rust/compile/macro32.rs | 19 ++++ gcc/testsuite/rust/compile/macro33.rs | 5 + gcc/testsuite/rust/compile/macro34.rs | 3 + gcc/testsuite/rust/compile/macro35.rs | 7 ++ gcc/testsuite/rust/compile/macro36.rs | 3 + gcc/testsuite/rust/compile/macro37.rs | 5 + gcc/testsuite/rust/compile/macro38.rs | 5 + gcc/testsuite/rust/compile/macro39.rs | 5 + gcc/testsuite/rust/compile/macro4.rs | 3 + gcc/testsuite/rust/compile/macro40.rs | 48 +++++++++ gcc/testsuite/rust/compile/macro41.rs | 13 +++ gcc/testsuite/rust/compile/macro42.rs | 32 ++++++ gcc/testsuite/rust/compile/macro5.rs | 3 + gcc/testsuite/rust/compile/macro6.rs | 11 +++ gcc/testsuite/rust/compile/macro7.rs | 13 +++ gcc/testsuite/rust/compile/macro8.rs | 12 +++ gcc/testsuite/rust/compile/macro9.rs | 17 ++++ gcc/testsuite/rust/compile/macro_return.rs | 10 ++ gcc/testsuite/rust/compile/match1.rs | 16 +++ gcc/testsuite/rust/compile/match2.rs | 15 +++ gcc/testsuite/rust/compile/match3.rs | 16 +++ gcc/testsuite/rust/compile/match4.rs | 16 +++ gcc/testsuite/rust/compile/match5.rs | 15 +++ gcc/testsuite/rust/compile/match6.rs | 18 ++++ gcc/testsuite/rust/compile/match7.rs | 12 +++ gcc/testsuite/rust/compile/method1.rs | 13 +++ gcc/testsuite/rust/compile/method2.rs | 16 +++ .../rust/compile/mismatch-crate-name.rs | 4 + .../rust/compile/missing_middle/both_path.rs | 3 + .../compile/missing_middle/explicit.not.rs | 1 + .../rust/compile/missing_middle/inner_path.rs | 3 + .../rust/compile/missing_middle/other.rs | 3 + .../rust/compile/missing_middle/outer_path.rs | 3 + .../rust/compile/missing_middle/sub/mod.rs | 3 + gcc/testsuite/rust/compile/missing_return1.rs | 6 ++ .../rust/compile/mod_missing_middle.rs | 29 ++++++ gcc/testsuite/rust/compile/never_type_err1.rs | 14 +++ gcc/testsuite/rust/compile/privacy1.rs | 11 +++ gcc/testsuite/rust/compile/privacy2.rs | 13 +++ gcc/testsuite/rust/compile/privacy3.rs | 28 ++++++ gcc/testsuite/rust/compile/privacy4.rs | 19 ++++ gcc/testsuite/rust/compile/privacy5.rs | 17 ++++ gcc/testsuite/rust/compile/privacy6.rs | 39 ++++++++ .../rust/compile/pub_restricted_1.rs | 13 +++ .../rust/compile/pub_restricted_2.rs | 18 ++++ .../rust/compile/pub_restricted_3.rs | 11 +++ .../compile/raw_identifiers_bad_keywords.rs | 3 + .../compile/raw_identifiers_underscore.rs | 3 + gcc/testsuite/rust/compile/rawbytestring.rs | Bin 0 -> 3234 bytes gcc/testsuite/rust/compile/redef_error1.rs | 8 ++ gcc/testsuite/rust/compile/redef_error2.rs | 4 + gcc/testsuite/rust/compile/redef_error3.rs | 9 ++ gcc/testsuite/rust/compile/redef_error4.rs | 27 ++++++ gcc/testsuite/rust/compile/redef_error5.rs | 8 ++ gcc/testsuite/rust/compile/redef_error6.rs | 13 +++ gcc/testsuite/rust/compile/reference1.rs | 6 ++ gcc/testsuite/rust/compile/self-path1.rs | 12 +++ gcc/testsuite/rust/compile/self-path2.rs | 21 ++++ gcc/testsuite/rust/compile/shadow1.rs | 7 ++ .../rust/compile/specify-crate-name.rs | 7 ++ gcc/testsuite/rust/compile/static_var1.rs | 5 + .../rust/compile/stmt_with_block_err1.rs | 17 ++++ gcc/testsuite/rust/compile/struct_align1.rs | 19 ++++ gcc/testsuite/rust/compile/struct_align2.rs | 18 ++++ gcc/testsuite/rust/compile/struct_init1.rs | 10 ++ gcc/testsuite/rust/compile/struct_pack1.rs | 19 ++++ gcc/testsuite/rust/compile/struct_pack2.rs | 18 ++++ gcc/testsuite/rust/compile/syntax-only.rs | 6 ++ gcc/testsuite/rust/compile/test_mod.rs | 6 ++ .../torture/all_doc_comment_line_blocks.rs | 45 +++++++++ .../all_doc_comment_line_blocks_crlf.rs | 48 +++++++++ .../torture/arithmetic_expressions1.rs | 30 ++++++ .../compile/torture/array_const_fold_1.rs | 2 + .../compile/torture/array_const_fold_2.rs | 3 + .../rust/compile/torture/array_function.rs | 8 ++ .../rust/compile/torture/array_type_infer.rs | 4 + .../rust/compile/torture/array_zero_length.rs | 4 + gcc/testsuite/rust/compile/torture/arrays1.rs | 9 ++ gcc/testsuite/rust/compile/torture/arrays2.rs | 8 ++ gcc/testsuite/rust/compile/torture/arrays3.rs | 6 ++ gcc/testsuite/rust/compile/torture/arrays4.rs | 6 ++ gcc/testsuite/rust/compile/torture/arrays5.rs | 6 ++ gcc/testsuite/rust/compile/torture/arrays6.rs | 10 ++ .../rust/compile/torture/arrays_index1.rs | 9 ++ .../rust/compile/torture/arrays_index2.rs | 4 + .../rust/compile/torture/arrays_index3.rs | 15 +++ .../rust/compile/torture/as_bool_char.rs | 36 +++++++ .../rust/compile/torture/associated_types1.rs | 12 +++ .../rust/compile/torture/autoderef1.rs | 15 +++ .../rust/compile/torture/block_expr1.rs | 29 ++++++ .../rust/compile/torture/block_expr2.rs | 15 +++ .../rust/compile/torture/block_expr3.rs | 14 +++ .../rust/compile/torture/block_expr4.rs | 8 ++ .../rust/compile/torture/block_expr5.rs | 40 ++++++++ .../compile/torture/block_expr_parser_bug.rs | 5 + gcc/testsuite/rust/compile/torture/bom.rs | 1 + .../rust/compile/torture/bom_comment.rs | 2 + .../rust/compile/torture/bom_shebang.rs | 2 + .../rust/compile/torture/bom_whitespace.rs | 2 + .../rust/compile/torture/bools_eq.rs | 18 ++++ gcc/testsuite/rust/compile/torture/borrow1.rs | 17 ++++ .../rust/compile/torture/borrow_function.rs | 5 + .../rust/compile/torture/break_function.rs | 10 ++ .../rust/compile/torture/byte_char_str.rs | 8 ++ .../rust/compile/torture/byte_str.rs | 4 + gcc/testsuite/rust/compile/torture/cast1.rs | 5 + gcc/testsuite/rust/compile/torture/cast2.rs | 5 + gcc/testsuite/rust/compile/torture/cast3.rs | 6 ++ .../rust/compile/torture/cfg_attr.rs | 7 ++ gcc/testsuite/rust/compile/torture/char1.rs | 4 + .../compile/torture/check-doc-attr-string.rs | 18 ++++ .../rust/compile/torture/coercion1.rs | 11 +++ .../rust/compile/torture/coercion2.rs | 20 ++++ .../rust/compile/torture/comparison_expr1.rs | 38 ++++++++ .../rust/compile/torture/compile.exp | 33 +++++++ .../torture/compound_assignment_expr1.rs | 23 +++++ .../rust/compile/torture/conditional.rs | 11 +++ .../rust/compile/torture/constant1.rs | 9 ++ .../rust/compile/torture/constant2.rs | 6 ++ .../rust/compile/torture/constant3.rs | 10 ++ .../rust/compile/torture/deadcode1.rs | 22 +++++ .../rust/compile/torture/deadcode2.rs | 10 ++ gcc/testsuite/rust/compile/torture/deref1.rs | 6 ++ .../rust/compile/torture/deref_function.rs | 10 ++ .../rust/compile/torture/doc_comment.rs | 16 +++ gcc/testsuite/rust/compile/torture/enum1.rs | 13 +++ .../rust/compile/torture/extern_mod1.rs | 6 ++ .../rust/compile/torture/extern_mod2.rs | 23 +++++ gcc/testsuite/rust/compile/torture/float1.rs | 9 ++ .../rust/compile/torture/float_types.rs | 13 +++ .../rust/compile/torture/forward_decl_1.rs | 11 +++ .../rust/compile/torture/forward_decl_2.rs | 6 ++ .../compile/torture/forward_decl_3-unsafe.rs | 13 +++ .../rust/compile/torture/forward_decl_3.rs | 11 +++ .../rust/compile/torture/forward_decl_4.rs | 9 ++ .../rust/compile/torture/forward_decl_5.rs | 19 ++++ gcc/testsuite/rust/compile/torture/func1.rs | 7 ++ gcc/testsuite/rust/compile/torture/func2.rs | 20 ++++ .../compile/torture/function_reference1.rs | 9 ++ .../compile/torture/function_reference2.rs | 9 ++ .../compile/torture/function_reference3.rs | 20 ++++ .../compile/torture/function_reference4.rs | 9 ++ .../rust/compile/torture/generics1.rs | 51 ++++++++++ .../rust/compile/torture/generics10.rs | 20 ++++ .../rust/compile/torture/generics11.rs | 8 ++ .../rust/compile/torture/generics12.rs | 17 ++++ .../rust/compile/torture/generics13.rs | 41 ++++++++ .../rust/compile/torture/generics14.rs | 20 ++++ .../rust/compile/torture/generics15.rs | 23 +++++ .../rust/compile/torture/generics16.rs | 31 ++++++ .../rust/compile/torture/generics17.rs | 19 ++++ .../rust/compile/torture/generics18.rs | 20 ++++ .../rust/compile/torture/generics19.rs | 12 +++ .../rust/compile/torture/generics2.rs | 45 +++++++++ .../rust/compile/torture/generics20.rs | 12 +++ .../rust/compile/torture/generics21.rs | 13 +++ .../rust/compile/torture/generics22.rs | 13 +++ .../rust/compile/torture/generics23.rs | 6 ++ .../rust/compile/torture/generics24.rs | 34 +++++++ .../rust/compile/torture/generics25.rs | 9 ++ .../rust/compile/torture/generics26.rs | 21 ++++ .../rust/compile/torture/generics27.rs | 16 +++ .../rust/compile/torture/generics28.rs | 18 ++++ .../rust/compile/torture/generics29.rs | 16 +++ .../rust/compile/torture/generics3.rs | 15 +++ .../rust/compile/torture/generics30.rs | 16 +++ .../rust/compile/torture/generics31.rs | 15 +++ .../rust/compile/torture/generics32.rs | 15 +++ .../rust/compile/torture/generics4.rs | 17 ++++ .../rust/compile/torture/generics5.rs | 10 ++ .../rust/compile/torture/generics6.rs | 16 +++ .../rust/compile/torture/generics7.rs | 14 +++ .../rust/compile/torture/generics8.rs | 18 ++++ .../rust/compile/torture/generics9.rs | 25 +++++ .../compile/torture/grouped_expr_function.rs | 6 ++ .../torture/identifier-missing-impl-1.rs | 19 ++++ gcc/testsuite/rust/compile/torture/if.rs | 19 ++++ gcc/testsuite/rust/compile/torture/if_elif.rs | 20 ++++ .../compile/torture/if_elif_else_expr1.rs | 14 +++ gcc/testsuite/rust/compile/torture/if_else.rs | 19 ++++ .../rust/compile/torture/ifunaryexpr.rs | 22 +++++ .../rust/compile/torture/impl_block1.rs | 23 +++++ .../rust/compile/torture/impl_block2.rs | 28 ++++++ .../rust/compile/torture/impl_block3.rs | 36 +++++++ .../rust/compile/torture/impl_block_unused.rs | 17 ++++ .../rust/compile/torture/implicit_returns1.rs | 73 ++++++++++++++ .../rust/compile/torture/infer_type1.rs | 4 + .../rust/compile/torture/inner_attributes.rs | 3 + .../compile/torture/integer_inference_var1.rs | 6 ++ .../compile/torture/integer_inference_var2.rs | 6 ++ .../compile/torture/integer_inference_var3.rs | 11 +++ .../compile/torture/integer_inference_var4.rs | 4 + .../compile/torture/integer_inference_var5.rs | 25 +++++ .../rust/compile/torture/integer_types.rs | 27 ++++++ .../rust/compile/torture/intrinsics-1.rs | 22 +++++ .../rust/compile/torture/intrinsics-2.rs | 22 +++++ .../torture/isolated_cr_block_comment.rs | 2 + .../torture/isolated_cr_line_comment.rs | 2 + .../rust/compile/torture/issue-1024.rs | 11 +++ .../rust/compile/torture/issue-1075.rs | 42 ++++++++ .../rust/compile/torture/issue-1432.rs | 77 +++++++++++++++ .../rust/compile/torture/issue-1434.rs | 53 ++++++++++ .../rust/compile/torture/issue-368.rs | 9 ++ .../rust/compile/torture/issue-808.rs | 20 ++++ .../rust/compile/torture/issue-862.rs | 74 ++++++++++++++ .../rust/compile/torture/issue-893-2.rs | 35 +++++++ .../rust/compile/torture/issue-893.rs | 11 +++ .../torture/lazybooleanexpr_function.rs | 14 +++ .../rust/compile/torture/lifetime1.rs | 7 ++ .../rust/compile/torture/literals1.rs | 11 +++ gcc/testsuite/rust/compile/torture/loop1.rs | 10 ++ gcc/testsuite/rust/compile/torture/loop2.rs | 14 +++ gcc/testsuite/rust/compile/torture/loop3.rs | 14 +++ gcc/testsuite/rust/compile/torture/loop4.rs | 7 ++ gcc/testsuite/rust/compile/torture/loop5.rs | 14 +++ gcc/testsuite/rust/compile/torture/loop6.rs | 11 +++ gcc/testsuite/rust/compile/torture/loop7.rs | 13 +++ .../rust/compile/torture/macro-issue1403.rs | 23 +++++ .../rust/compile/torture/macro-issue1426.rs | 32 ++++++ .../rust/compile/torture/macro_as_expr.rs | 14 +++ gcc/testsuite/rust/compile/torture/match1.rs | 16 +++ .../rust/compile/torture/methods1.rs | 41 ++++++++ .../rust/compile/torture/methods2.rs | 43 +++++++++ .../rust/compile/torture/methods3.rs | 44 +++++++++ .../rust/compile/torture/mod-nameresolve.rs | 5 + gcc/testsuite/rust/compile/torture/mod1.rs | 11 +++ gcc/testsuite/rust/compile/torture/mod2.rs | 13 +++ gcc/testsuite/rust/compile/torture/mod3.rs | 22 +++++ .../rust/compile/torture/modules/mod.rs | 3 + .../compile/torture/modules/valid_path.rs | 1 + .../rust/compile/torture/must_use1.rs | 16 +++ .../rust/compile/torture/must_use2.rs | 16 +++ .../rust/compile/torture/name_resolve1.rs | 23 +++++ .../rust/compile/torture/negation_function.rs | 7 ++ .../rust/compile/torture/nested_fn1.rs | 10 ++ .../rust/compile/torture/nested_fn2.rs | 11 +++ .../rust/compile/torture/nested_struct1.rs | 20 ++++ .../rust/compile/torture/never_type1.rs | 22 +++++ .../rust/compile/torture/not_shebang.rs | 3 + .../torture/not_shebang_block_comment.rs | 1 + .../compile/torture/not_shebang_comment.rs | 3 + .../torture/not_shebang_multiline_comment.rs | 7 ++ .../compile/torture/not_shebang_spaces.rs | 6 ++ .../rust/compile/torture/parameter_usage1.rs | 8 ++ gcc/testsuite/rust/compile/torture/parens1.rs | 5 + .../rust/compile/torture/pointer1.rs | 9 ++ .../rust/compile/torture/primconsts.rs | 72 ++++++++++++++ .../rust/compile/torture/prims_struct_eq.rs | 91 ++++++++++++++++++ .../rust/compile/torture/range-lang-item1.rs | 32 ++++++ .../rust/compile/torture/raw_identifiers.rs | 3 + .../torture/raw_identifiers_keywords.rs | 3 + .../rust/compile/torture/recursive_fn1.rs | 12 +++ .../rust/compile/torture/return_function.rs | 5 + .../rust/compile/torture/scoping1.rs | 11 +++ .../rust/compile/torture/self_type1.rs | 12 +++ gcc/testsuite/rust/compile/torture/shadow1.rs | 6 ++ gcc/testsuite/rust/compile/torture/shadow2.rs | 5 + gcc/testsuite/rust/compile/torture/shebang.rs | 3 + .../rust/compile/torture/shebang_plus_attr.rs | 3 + .../compile/torture/shebang_plus_attr2.rs | 3 + .../rust/compile/torture/static_function.rs | 8 ++ .../rust/compile/torture/static_var1.rs | 6 ++ .../rust/compile/torture/stmt_with_block1.rs | 13 +++ gcc/testsuite/rust/compile/torture/str1.rs | 7 ++ .../rust/compile/torture/struct_access1.rs | 12 +++ .../compile/torture/struct_base_init_1.rs | 13 +++ .../rust/compile/torture/struct_decl.rs | 14 +++ .../rust/compile/torture/struct_init.rs | 11 +++ .../rust/compile/torture/struct_init_10.rs | 9 ++ .../rust/compile/torture/struct_init_11.rs | 34 +++++++ .../rust/compile/torture/struct_init_2.rs | 6 ++ .../rust/compile/torture/struct_init_3.rs | 13 +++ .../rust/compile/torture/struct_init_4.rs | 13 +++ .../rust/compile/torture/struct_init_5.rs | 10 ++ .../rust/compile/torture/struct_init_6.rs | 11 +++ .../rust/compile/torture/struct_init_7.rs | 11 +++ .../rust/compile/torture/struct_init_8.rs | 7 ++ .../rust/compile/torture/struct_init_9.rs | 6 ++ .../rust/compile/torture/top_attr.rs | 5 + gcc/testsuite/rust/compile/torture/traits1.rs | 16 +++ .../rust/compile/torture/traits10.rs | 30 ++++++ .../rust/compile/torture/traits11.rs | 31 ++++++ .../rust/compile/torture/traits12.rs | 29 ++++++ .../rust/compile/torture/traits13.rs | 17 ++++ .../rust/compile/torture/traits14.rs | 23 +++++ .../rust/compile/torture/traits15.rs | 23 +++++ .../rust/compile/torture/traits16.rs | 20 ++++ .../rust/compile/torture/traits17.rs | 23 +++++ .../rust/compile/torture/traits18.rs | 5 + .../rust/compile/torture/traits19.rs | 33 +++++++ gcc/testsuite/rust/compile/torture/traits2.rs | 16 +++ gcc/testsuite/rust/compile/torture/traits3.rs | 15 +++ gcc/testsuite/rust/compile/torture/traits4.rs | 21 ++++ gcc/testsuite/rust/compile/torture/traits5.rs | 21 ++++ gcc/testsuite/rust/compile/torture/traits6.rs | 20 ++++ gcc/testsuite/rust/compile/torture/traits7.rs | 19 ++++ gcc/testsuite/rust/compile/torture/traits8.rs | 21 ++++ gcc/testsuite/rust/compile/torture/traits9.rs | 27 ++++++ .../compile/torture/transmute-size-check-1.rs | 11 +++ .../rust/compile/torture/transmute1.rs | 11 +++ gcc/testsuite/rust/compile/torture/tuple1.rs | 6 ++ gcc/testsuite/rust/compile/torture/tuple2.rs | 5 + gcc/testsuite/rust/compile/torture/tuple3.rs | 9 ++ .../compile/torture/tuple_enum_variants.rs | 23 +++++ .../compile/torture/tuple_field_access.rs | 6 ++ .../rust/compile/torture/tuple_function.rs | 6 ++ .../rust/compile/torture/tuple_index.rs | 32 ++++++ .../rust/compile/torture/tuple_struct1.rs | 6 ++ .../rust/compile/torture/tuple_struct2.rs | 11 +++ .../rust/compile/torture/tuple_struct_unit.rs | 11 +++ .../compile/torture/tuple_struct_unused.rs | 4 + .../rust/compile/torture/type-alias1.rs | 6 ++ .../rust/compile/torture/type-alias2.rs | 8 ++ .../rust/compile/torture/type_infer1.rs | 24 +++++ .../rust/compile/torture/type_infer2.rs | 9 ++ .../rust/compile/torture/type_infer3.rs | 14 +++ .../rust/compile/torture/type_infer4.rs | 11 +++ .../rust/compile/torture/type_infer5.rs | 13 +++ .../rust/compile/torture/type_infer6.rs | 14 +++ .../rust/compile/torture/unary_operators.rs | 8 ++ .../rust/compile/torture/undended-string-1.rs | 5 + .../rust/compile/torture/undended-string-2.rs | 5 + .../rust/compile/torture/underscore_id.rs | 4 + gcc/testsuite/rust/compile/torture/union.rs | 32 ++++++ .../rust/compile/torture/union_union.rs | 27 ++++++ .../rust/compile/torture/unit_type1.rs | 7 ++ .../rust/compile/torture/unit_type2.rs | 8 ++ .../rust/compile/torture/unit_type3.rs | 6 ++ .../rust/compile/torture/unit_type4.rs | 5 + .../rust/compile/torture/unit_type5.rs | 8 ++ gcc/testsuite/rust/compile/torture/unsafe1.rs | 12 +++ gcc/testsuite/rust/compile/torture/unsafe2.rs | 4 + gcc/testsuite/rust/compile/torture/unsafe3.rs | 9 ++ gcc/testsuite/rust/compile/torture/unsafe4.rs | 12 +++ gcc/testsuite/rust/compile/torture/unused.rs | 17 ++++ gcc/testsuite/rust/compile/torture/unused1.rs | 15 +++ .../rust/compile/torture/unused_struct.rs | 7 ++ .../compile/torture/unused_struct_field.rs | 9 ++ gcc/testsuite/rust/compile/torture/usize1.rs | 6 ++ .../torture/very-broken-attr-string.rs | 3 + .../rust/compile/torture/while_function.rs | 10 ++ gcc/testsuite/rust/compile/traits1.rs | 13 +++ gcc/testsuite/rust/compile/traits10.rs | 15 +++ gcc/testsuite/rust/compile/traits11.rs | 19 ++++ gcc/testsuite/rust/compile/traits12.rs | 20 ++++ gcc/testsuite/rust/compile/traits2.rs | 14 +++ gcc/testsuite/rust/compile/traits3.rs | 22 +++++ gcc/testsuite/rust/compile/traits4.rs | 16 +++ gcc/testsuite/rust/compile/traits5.rs | 9 ++ gcc/testsuite/rust/compile/traits6.rs | 15 +++ gcc/testsuite/rust/compile/traits7.rs | 24 +++++ gcc/testsuite/rust/compile/traits8.rs | 35 +++++++ gcc/testsuite/rust/compile/traits9.rs | 13 +++ gcc/testsuite/rust/compile/tuple1.rs | 5 + gcc/testsuite/rust/compile/tuple_struct1.rs | 8 ++ gcc/testsuite/rust/compile/tuple_struct2.rs | 5 + gcc/testsuite/rust/compile/tuple_struct3.rs | 6 ++ gcc/testsuite/rust/compile/type-alias1.rs | 6 ++ gcc/testsuite/rust/compile/type-bindings1.rs | 10 ++ gcc/testsuite/rust/compile/unary_negation.rs | 9 ++ gcc/testsuite/rust/compile/unary_not.rs | 9 ++ .../rust/compile/unconstrained_type_param.rs | 12 +++ gcc/testsuite/rust/compile/unicode_escape.rs | 60 ++++++++++++ gcc/testsuite/rust/compile/unsafe1.rs | 14 +++ gcc/testsuite/rust/compile/unsafe10.rs | 12 +++ gcc/testsuite/rust/compile/unsafe2.rs | 16 +++ gcc/testsuite/rust/compile/unsafe3.rs | 10 ++ gcc/testsuite/rust/compile/unsafe4.rs | 29 ++++++ gcc/testsuite/rust/compile/unsafe5.rs | 4 + gcc/testsuite/rust/compile/unsafe6.rs | 14 +++ gcc/testsuite/rust/compile/unsafe7.rs | 9 ++ gcc/testsuite/rust/compile/unsafe8.rs | 14 +++ gcc/testsuite/rust/compile/unsafe9.rs | 10 ++ .../rust/compile/unterminated_c_comment.rs | 2 + gcc/testsuite/rust/compile/use_1.rs | 16 +++ gcc/testsuite/rust/compile/usize1.rs | 6 ++ .../rust/compile/xfail/lifetime_param.rs | 11 +++ .../rust/compile/xfail/struct_field_vis.rs | 15 +++ gcc/testsuite/rust/compile/xfail/xfail.exp | 63 ++++++++++++ 531 files changed, 7556 insertions(+) create mode 100644 gcc/testsuite/rust/compile/abi-options1.rs create mode 100644 gcc/testsuite/rust/compile/array3.rs create mode 100644 gcc/testsuite/rust/compile/array_empty_list.rs create mode 100644 gcc/testsuite/rust/compile/arrays1.rs create mode 100644 gcc/testsuite/rust/compile/arrays2.rs create mode 100644 gcc/testsuite/rust/compile/attr-mismatch-crate-name.rs create mode 100644 gcc/testsuite/rust/compile/attr_cold.rs create mode 100644 gcc/testsuite/rust/compile/attr_deprecated.rs create mode 100644 gcc/testsuite/rust/compile/attr_deprecated_2.rs create mode 100644 gcc/testsuite/rust/compile/bad-crate-name.rs create mode 100644 gcc/testsuite/rust/compile/bad=file-name.rs create mode 100644 gcc/testsuite/rust/compile/bad_as_bool_char.rs create mode 100644 gcc/testsuite/rust/compile/bad_file_name.txt.rs create mode 100644 gcc/testsuite/rust/compile/bad_inner_doc.rs create mode 100644 gcc/testsuite/rust/compile/bad_pub_enumitems.rs create mode 100644 gcc/testsuite/rust/compile/bad_stmt_enums.rs create mode 100644 gcc/testsuite/rust/compile/bad_toplevel_enums.rs create mode 100644 gcc/testsuite/rust/compile/bad_tuple_index.rs create mode 100644 gcc/testsuite/rust/compile/bad_type1.rs create mode 100644 gcc/testsuite/rust/compile/bad_type2.rs create mode 100644 gcc/testsuite/rust/compile/break1.rs create mode 100644 gcc/testsuite/rust/compile/break2.rs create mode 100644 gcc/testsuite/rust/compile/builtin_macro_compile_error.rs create mode 100644 gcc/testsuite/rust/compile/builtin_macro_concat.rs create mode 100644 gcc/testsuite/rust/compile/builtin_macro_env.rs create mode 100644 gcc/testsuite/rust/compile/builtin_macro_include_bytes.rs create mode 100644 gcc/testsuite/rust/compile/builtin_macro_include_str.rs create mode 100644 gcc/testsuite/rust/compile/builtin_macro_not_found.rs create mode 100644 gcc/testsuite/rust/compile/bytecharstring.rs create mode 100644 gcc/testsuite/rust/compile/canonical_paths1.rs create mode 100644 gcc/testsuite/rust/compile/cast1.rs create mode 100644 gcc/testsuite/rust/compile/cfg1.rs create mode 100644 gcc/testsuite/rust/compile/cfg2.rs create mode 100644 gcc/testsuite/rust/compile/cfg3.rs create mode 100644 gcc/testsuite/rust/compile/cfg4.rs create mode 100644 gcc/testsuite/rust/compile/cfg5.rs create mode 100644 gcc/testsuite/rust/compile/compile.exp create mode 100644 gcc/testsuite/rust/compile/complex-path1.rs create mode 100644 gcc/testsuite/rust/compile/const-issue1440.rs create mode 100644 gcc/testsuite/rust/compile/const1.rs create mode 100644 gcc/testsuite/rust/compile/const2.rs create mode 100644 gcc/testsuite/rust/compile/const3.rs create mode 100644 gcc/testsuite/rust/compile/const_generics_1.rs create mode 100644 gcc/testsuite/rust/compile/const_generics_2.rs create mode 100644 gcc/testsuite/rust/compile/const_generics_3.rs create mode 100644 gcc/testsuite/rust/compile/const_generics_4.rs create mode 100644 gcc/testsuite/rust/compile/const_generics_5.rs create mode 100644 gcc/testsuite/rust/compile/const_generics_6.rs create mode 100644 gcc/testsuite/rust/compile/continue1.rs create mode 100644 gcc/testsuite/rust/compile/deadcode_err1.rs create mode 100644 gcc/testsuite/rust/compile/deadcode_err2.rs create mode 100644 gcc/testsuite/rust/compile/debug-diagnostics-default.rs create mode 100644 gcc/testsuite/rust/compile/debug-diagnostics-off.rs create mode 100644 gcc/testsuite/rust/compile/debug-diagnostics-on.rs create mode 100644 gcc/testsuite/rust/compile/doc_isolated_cr_block_comment.rs create mode 100644 gcc/testsuite/rust/compile/doc_isolated_cr_inner_block_comment.rs create mode 100644 gcc/testsuite/rust/compile/doc_isolated_cr_inner_line_comment.rs create mode 100644 gcc/testsuite/rust/compile/doc_isolated_cr_line_comment.rs create mode 100644 gcc/testsuite/rust/compile/dup_fields.rs create mode 100644 gcc/testsuite/rust/compile/empty_comment_before_match.rs create mode 100644 gcc/testsuite/rust/compile/expected_type_args2.rs create mode 100644 gcc/testsuite/rust/compile/expected_type_args3.rs create mode 100644 gcc/testsuite/rust/compile/func1.rs create mode 100644 gcc/testsuite/rust/compile/func2.rs create mode 100644 gcc/testsuite/rust/compile/func3.rs create mode 100644 gcc/testsuite/rust/compile/func4.rs create mode 100644 gcc/testsuite/rust/compile/func5.rs create mode 100644 gcc/testsuite/rust/compile/generic-default1.rs create mode 100644 gcc/testsuite/rust/compile/generics1.rs create mode 100644 gcc/testsuite/rust/compile/generics10.rs create mode 100644 gcc/testsuite/rust/compile/generics11.rs create mode 100644 gcc/testsuite/rust/compile/generics12.rs create mode 100644 gcc/testsuite/rust/compile/generics13.rs create mode 100644 gcc/testsuite/rust/compile/generics2.rs create mode 100644 gcc/testsuite/rust/compile/generics3.rs create mode 100644 gcc/testsuite/rust/compile/generics4.rs create mode 100644 gcc/testsuite/rust/compile/generics5.rs create mode 100644 gcc/testsuite/rust/compile/generics6.rs create mode 100644 gcc/testsuite/rust/compile/generics7.rs create mode 100644 gcc/testsuite/rust/compile/generics8.rs create mode 100644 gcc/testsuite/rust/compile/generics9.rs create mode 100644 gcc/testsuite/rust/compile/implicit_returns_err1.rs create mode 100644 gcc/testsuite/rust/compile/implicit_returns_err2.rs create mode 100644 gcc/testsuite/rust/compile/implicit_returns_err3.rs create mode 100644 gcc/testsuite/rust/compile/implicit_returns_err4.rs create mode 100644 gcc/testsuite/rust/compile/infer-crate-name.rs create mode 100644 gcc/testsuite/rust/compile/inline_1.rs create mode 100644 gcc/testsuite/rust/compile/inline_2.rs create mode 100644 gcc/testsuite/rust/compile/issue-1005.rs create mode 100644 gcc/testsuite/rust/compile/issue-1019.rs create mode 100644 gcc/testsuite/rust/compile/issue-1023.rs create mode 100644 gcc/testsuite/rust/compile/issue-1031.rs create mode 100644 gcc/testsuite/rust/compile/issue-1034.rs create mode 100644 gcc/testsuite/rust/compile/issue-1089.rs create mode 100644 gcc/testsuite/rust/compile/issue-1128.rs create mode 100644 gcc/testsuite/rust/compile/issue-1129-1.rs create mode 100644 gcc/testsuite/rust/compile/issue-1129-2.rs create mode 100644 gcc/testsuite/rust/compile/issue-1130.rs create mode 100644 gcc/testsuite/rust/compile/issue-1131.rs create mode 100644 gcc/testsuite/rust/compile/issue-1152.rs create mode 100644 gcc/testsuite/rust/compile/issue-1165.rs create mode 100644 gcc/testsuite/rust/compile/issue-1173.rs create mode 100644 gcc/testsuite/rust/compile/issue-1226.rs create mode 100644 gcc/testsuite/rust/compile/issue-1234.rs create mode 100644 gcc/testsuite/rust/compile/issue-1235.rs create mode 100644 gcc/testsuite/rust/compile/issue-1237.rs create mode 100644 gcc/testsuite/rust/compile/issue-1251.rs create mode 100644 gcc/testsuite/rust/compile/issue-1271.rs create mode 100644 gcc/testsuite/rust/compile/issue-1289.rs create mode 100644 gcc/testsuite/rust/compile/issue-1323-1.rs create mode 100644 gcc/testsuite/rust/compile/issue-1323-2.rs create mode 100644 gcc/testsuite/rust/compile/issue-1383.rs create mode 100644 gcc/testsuite/rust/compile/issue-1393.rs create mode 100644 gcc/testsuite/rust/compile/issue-1447.rs create mode 100644 gcc/testsuite/rust/compile/issue-407-2.rs create mode 100644 gcc/testsuite/rust/compile/issue-407.rs create mode 100644 gcc/testsuite/rust/compile/issue-557.rs create mode 100644 gcc/testsuite/rust/compile/issue-635-1.rs create mode 100644 gcc/testsuite/rust/compile/issue-635-2.rs create mode 100644 gcc/testsuite/rust/compile/lookup_err1.rs create mode 100644 gcc/testsuite/rust/compile/macro-issue1053-2.rs create mode 100644 gcc/testsuite/rust/compile/macro-issue1053.rs create mode 100644 gcc/testsuite/rust/compile/macro-issue1224.rs create mode 100644 gcc/testsuite/rust/compile/macro-issue1233.rs create mode 100644 gcc/testsuite/rust/compile/macro-issue1395-2.rs create mode 100644 gcc/testsuite/rust/compile/macro-issue1395.rs create mode 100644 gcc/testsuite/rust/compile/macro-issue1400-2.rs create mode 100644 gcc/testsuite/rust/compile/macro-issue1400.rs create mode 100644 gcc/testsuite/rust/compile/macro1.rs create mode 100644 gcc/testsuite/rust/compile/macro10.rs create mode 100644 gcc/testsuite/rust/compile/macro11.rs create mode 100644 gcc/testsuite/rust/compile/macro12.rs create mode 100644 gcc/testsuite/rust/compile/macro13.rs create mode 100644 gcc/testsuite/rust/compile/macro14.rs create mode 100644 gcc/testsuite/rust/compile/macro15.rs create mode 100644 gcc/testsuite/rust/compile/macro16.rs create mode 100644 gcc/testsuite/rust/compile/macro17.rs create mode 100644 gcc/testsuite/rust/compile/macro18.rs create mode 100644 gcc/testsuite/rust/compile/macro19.rs create mode 100644 gcc/testsuite/rust/compile/macro2.rs create mode 100644 gcc/testsuite/rust/compile/macro20.rs create mode 100644 gcc/testsuite/rust/compile/macro21.rs create mode 100644 gcc/testsuite/rust/compile/macro22.rs create mode 100644 gcc/testsuite/rust/compile/macro23.rs create mode 100644 gcc/testsuite/rust/compile/macro25.rs create mode 100644 gcc/testsuite/rust/compile/macro26.rs create mode 100644 gcc/testsuite/rust/compile/macro27.rs create mode 100644 gcc/testsuite/rust/compile/macro28.rs create mode 100644 gcc/testsuite/rust/compile/macro29.rs create mode 100644 gcc/testsuite/rust/compile/macro3.rs create mode 100644 gcc/testsuite/rust/compile/macro30.rs create mode 100644 gcc/testsuite/rust/compile/macro31.rs create mode 100644 gcc/testsuite/rust/compile/macro32.rs create mode 100644 gcc/testsuite/rust/compile/macro33.rs create mode 100644 gcc/testsuite/rust/compile/macro34.rs create mode 100644 gcc/testsuite/rust/compile/macro35.rs create mode 100644 gcc/testsuite/rust/compile/macro36.rs create mode 100644 gcc/testsuite/rust/compile/macro37.rs create mode 100644 gcc/testsuite/rust/compile/macro38.rs create mode 100644 gcc/testsuite/rust/compile/macro39.rs create mode 100644 gcc/testsuite/rust/compile/macro4.rs create mode 100644 gcc/testsuite/rust/compile/macro40.rs create mode 100644 gcc/testsuite/rust/compile/macro41.rs create mode 100644 gcc/testsuite/rust/compile/macro42.rs create mode 100644 gcc/testsuite/rust/compile/macro5.rs create mode 100644 gcc/testsuite/rust/compile/macro6.rs create mode 100644 gcc/testsuite/rust/compile/macro7.rs create mode 100644 gcc/testsuite/rust/compile/macro8.rs create mode 100644 gcc/testsuite/rust/compile/macro9.rs create mode 100644 gcc/testsuite/rust/compile/macro_return.rs create mode 100644 gcc/testsuite/rust/compile/match1.rs create mode 100644 gcc/testsuite/rust/compile/match2.rs create mode 100644 gcc/testsuite/rust/compile/match3.rs create mode 100644 gcc/testsuite/rust/compile/match4.rs create mode 100644 gcc/testsuite/rust/compile/match5.rs create mode 100644 gcc/testsuite/rust/compile/match6.rs create mode 100644 gcc/testsuite/rust/compile/match7.rs create mode 100644 gcc/testsuite/rust/compile/method1.rs create mode 100644 gcc/testsuite/rust/compile/method2.rs create mode 100644 gcc/testsuite/rust/compile/mismatch-crate-name.rs create mode 100644 gcc/testsuite/rust/compile/missing_middle/both_path.rs create mode 100644 gcc/testsuite/rust/compile/missing_middle/explicit.not.rs create mode 100644 gcc/testsuite/rust/compile/missing_middle/inner_path.rs create mode 100644 gcc/testsuite/rust/compile/missing_middle/other.rs create mode 100644 gcc/testsuite/rust/compile/missing_middle/outer_path.rs create mode 100644 gcc/testsuite/rust/compile/missing_middle/sub/mod.rs create mode 100644 gcc/testsuite/rust/compile/missing_return1.rs create mode 100644 gcc/testsuite/rust/compile/mod_missing_middle.rs create mode 100644 gcc/testsuite/rust/compile/never_type_err1.rs create mode 100644 gcc/testsuite/rust/compile/privacy1.rs create mode 100644 gcc/testsuite/rust/compile/privacy2.rs create mode 100644 gcc/testsuite/rust/compile/privacy3.rs create mode 100644 gcc/testsuite/rust/compile/privacy4.rs create mode 100644 gcc/testsuite/rust/compile/privacy5.rs create mode 100644 gcc/testsuite/rust/compile/privacy6.rs create mode 100644 gcc/testsuite/rust/compile/pub_restricted_1.rs create mode 100644 gcc/testsuite/rust/compile/pub_restricted_2.rs create mode 100644 gcc/testsuite/rust/compile/pub_restricted_3.rs create mode 100644 gcc/testsuite/rust/compile/raw_identifiers_bad_keywords.rs create mode 100644 gcc/testsuite/rust/compile/raw_identifiers_underscore.rs create mode 100644 gcc/testsuite/rust/compile/rawbytestring.rs create mode 100644 gcc/testsuite/rust/compile/redef_error1.rs create mode 100644 gcc/testsuite/rust/compile/redef_error2.rs create mode 100644 gcc/testsuite/rust/compile/redef_error3.rs create mode 100644 gcc/testsuite/rust/compile/redef_error4.rs create mode 100644 gcc/testsuite/rust/compile/redef_error5.rs create mode 100644 gcc/testsuite/rust/compile/redef_error6.rs create mode 100644 gcc/testsuite/rust/compile/reference1.rs create mode 100644 gcc/testsuite/rust/compile/self-path1.rs create mode 100644 gcc/testsuite/rust/compile/self-path2.rs create mode 100644 gcc/testsuite/rust/compile/shadow1.rs create mode 100644 gcc/testsuite/rust/compile/specify-crate-name.rs create mode 100644 gcc/testsuite/rust/compile/static_var1.rs create mode 100644 gcc/testsuite/rust/compile/stmt_with_block_err1.rs create mode 100644 gcc/testsuite/rust/compile/struct_align1.rs create mode 100644 gcc/testsuite/rust/compile/struct_align2.rs create mode 100644 gcc/testsuite/rust/compile/struct_init1.rs create mode 100644 gcc/testsuite/rust/compile/struct_pack1.rs create mode 100644 gcc/testsuite/rust/compile/struct_pack2.rs create mode 100644 gcc/testsuite/rust/compile/syntax-only.rs create mode 100644 gcc/testsuite/rust/compile/test_mod.rs create mode 100644 gcc/testsuite/rust/compile/torture/all_doc_comment_line_blocks.rs create mode 100644 gcc/testsuite/rust/compile/torture/all_doc_comment_line_blocks_crlf.rs create mode 100644 gcc/testsuite/rust/compile/torture/arithmetic_expressions1.rs create mode 100644 gcc/testsuite/rust/compile/torture/array_const_fold_1.rs create mode 100644 gcc/testsuite/rust/compile/torture/array_const_fold_2.rs create mode 100644 gcc/testsuite/rust/compile/torture/array_function.rs create mode 100644 gcc/testsuite/rust/compile/torture/array_type_infer.rs create mode 100644 gcc/testsuite/rust/compile/torture/array_zero_length.rs create mode 100644 gcc/testsuite/rust/compile/torture/arrays1.rs create mode 100644 gcc/testsuite/rust/compile/torture/arrays2.rs create mode 100644 gcc/testsuite/rust/compile/torture/arrays3.rs create mode 100644 gcc/testsuite/rust/compile/torture/arrays4.rs create mode 100644 gcc/testsuite/rust/compile/torture/arrays5.rs create mode 100644 gcc/testsuite/rust/compile/torture/arrays6.rs create mode 100644 gcc/testsuite/rust/compile/torture/arrays_index1.rs create mode 100644 gcc/testsuite/rust/compile/torture/arrays_index2.rs create mode 100644 gcc/testsuite/rust/compile/torture/arrays_index3.rs create mode 100644 gcc/testsuite/rust/compile/torture/as_bool_char.rs create mode 100644 gcc/testsuite/rust/compile/torture/associated_types1.rs create mode 100644 gcc/testsuite/rust/compile/torture/autoderef1.rs create mode 100644 gcc/testsuite/rust/compile/torture/block_expr1.rs create mode 100644 gcc/testsuite/rust/compile/torture/block_expr2.rs create mode 100644 gcc/testsuite/rust/compile/torture/block_expr3.rs create mode 100644 gcc/testsuite/rust/compile/torture/block_expr4.rs create mode 100644 gcc/testsuite/rust/compile/torture/block_expr5.rs create mode 100644 gcc/testsuite/rust/compile/torture/block_expr_parser_bug.rs create mode 100644 gcc/testsuite/rust/compile/torture/bom.rs create mode 100644 gcc/testsuite/rust/compile/torture/bom_comment.rs create mode 100644 gcc/testsuite/rust/compile/torture/bom_shebang.rs create mode 100644 gcc/testsuite/rust/compile/torture/bom_whitespace.rs create mode 100644 gcc/testsuite/rust/compile/torture/bools_eq.rs create mode 100644 gcc/testsuite/rust/compile/torture/borrow1.rs create mode 100644 gcc/testsuite/rust/compile/torture/borrow_function.rs create mode 100644 gcc/testsuite/rust/compile/torture/break_function.rs create mode 100644 gcc/testsuite/rust/compile/torture/byte_char_str.rs create mode 100644 gcc/testsuite/rust/compile/torture/byte_str.rs create mode 100644 gcc/testsuite/rust/compile/torture/cast1.rs create mode 100644 gcc/testsuite/rust/compile/torture/cast2.rs create mode 100644 gcc/testsuite/rust/compile/torture/cast3.rs create mode 100644 gcc/testsuite/rust/compile/torture/cfg_attr.rs create mode 100644 gcc/testsuite/rust/compile/torture/char1.rs create mode 100644 gcc/testsuite/rust/compile/torture/check-doc-attr-string.rs create mode 100644 gcc/testsuite/rust/compile/torture/coercion1.rs create mode 100644 gcc/testsuite/rust/compile/torture/coercion2.rs create mode 100644 gcc/testsuite/rust/compile/torture/comparison_expr1.rs create mode 100644 gcc/testsuite/rust/compile/torture/compile.exp create mode 100644 gcc/testsuite/rust/compile/torture/compound_assignment_expr1.rs create mode 100644 gcc/testsuite/rust/compile/torture/conditional.rs create mode 100644 gcc/testsuite/rust/compile/torture/constant1.rs create mode 100644 gcc/testsuite/rust/compile/torture/constant2.rs create mode 100644 gcc/testsuite/rust/compile/torture/constant3.rs create mode 100644 gcc/testsuite/rust/compile/torture/deadcode1.rs create mode 100644 gcc/testsuite/rust/compile/torture/deadcode2.rs create mode 100644 gcc/testsuite/rust/compile/torture/deref1.rs create mode 100644 gcc/testsuite/rust/compile/torture/deref_function.rs create mode 100644 gcc/testsuite/rust/compile/torture/doc_comment.rs create mode 100644 gcc/testsuite/rust/compile/torture/enum1.rs create mode 100644 gcc/testsuite/rust/compile/torture/extern_mod1.rs create mode 100644 gcc/testsuite/rust/compile/torture/extern_mod2.rs create mode 100644 gcc/testsuite/rust/compile/torture/float1.rs create mode 100644 gcc/testsuite/rust/compile/torture/float_types.rs create mode 100644 gcc/testsuite/rust/compile/torture/forward_decl_1.rs create mode 100644 gcc/testsuite/rust/compile/torture/forward_decl_2.rs create mode 100644 gcc/testsuite/rust/compile/torture/forward_decl_3-unsafe.rs create mode 100644 gcc/testsuite/rust/compile/torture/forward_decl_3.rs create mode 100644 gcc/testsuite/rust/compile/torture/forward_decl_4.rs create mode 100644 gcc/testsuite/rust/compile/torture/forward_decl_5.rs create mode 100644 gcc/testsuite/rust/compile/torture/func1.rs create mode 100644 gcc/testsuite/rust/compile/torture/func2.rs create mode 100644 gcc/testsuite/rust/compile/torture/function_reference1.rs create mode 100644 gcc/testsuite/rust/compile/torture/function_reference2.rs create mode 100644 gcc/testsuite/rust/compile/torture/function_reference3.rs create mode 100644 gcc/testsuite/rust/compile/torture/function_reference4.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics1.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics10.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics11.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics12.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics13.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics14.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics15.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics16.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics17.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics18.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics19.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics2.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics20.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics21.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics22.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics23.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics24.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics25.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics26.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics27.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics28.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics29.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics3.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics30.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics31.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics32.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics4.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics5.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics6.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics7.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics8.rs create mode 100644 gcc/testsuite/rust/compile/torture/generics9.rs create mode 100644 gcc/testsuite/rust/compile/torture/grouped_expr_function.rs create mode 100644 gcc/testsuite/rust/compile/torture/identifier-missing-impl-1.rs create mode 100644 gcc/testsuite/rust/compile/torture/if.rs create mode 100644 gcc/testsuite/rust/compile/torture/if_elif.rs create mode 100644 gcc/testsuite/rust/compile/torture/if_elif_else_expr1.rs create mode 100644 gcc/testsuite/rust/compile/torture/if_else.rs create mode 100644 gcc/testsuite/rust/compile/torture/ifunaryexpr.rs create mode 100644 gcc/testsuite/rust/compile/torture/impl_block1.rs create mode 100644 gcc/testsuite/rust/compile/torture/impl_block2.rs create mode 100644 gcc/testsuite/rust/compile/torture/impl_block3.rs create mode 100644 gcc/testsuite/rust/compile/torture/impl_block_unused.rs create mode 100644 gcc/testsuite/rust/compile/torture/implicit_returns1.rs create mode 100644 gcc/testsuite/rust/compile/torture/infer_type1.rs create mode 100644 gcc/testsuite/rust/compile/torture/inner_attributes.rs create mode 100644 gcc/testsuite/rust/compile/torture/integer_inference_var1.rs create mode 100644 gcc/testsuite/rust/compile/torture/integer_inference_var2.rs create mode 100644 gcc/testsuite/rust/compile/torture/integer_inference_var3.rs create mode 100644 gcc/testsuite/rust/compile/torture/integer_inference_var4.rs create mode 100644 gcc/testsuite/rust/compile/torture/integer_inference_var5.rs create mode 100644 gcc/testsuite/rust/compile/torture/integer_types.rs create mode 100644 gcc/testsuite/rust/compile/torture/intrinsics-1.rs create mode 100644 gcc/testsuite/rust/compile/torture/intrinsics-2.rs create mode 100644 gcc/testsuite/rust/compile/torture/isolated_cr_block_comment.rs create mode 100644 gcc/testsuite/rust/compile/torture/isolated_cr_line_comment.rs create mode 100644 gcc/testsuite/rust/compile/torture/issue-1024.rs create mode 100644 gcc/testsuite/rust/compile/torture/issue-1075.rs create mode 100644 gcc/testsuite/rust/compile/torture/issue-1432.rs create mode 100644 gcc/testsuite/rust/compile/torture/issue-1434.rs create mode 100644 gcc/testsuite/rust/compile/torture/issue-368.rs create mode 100644 gcc/testsuite/rust/compile/torture/issue-808.rs create mode 100644 gcc/testsuite/rust/compile/torture/issue-862.rs create mode 100644 gcc/testsuite/rust/compile/torture/issue-893-2.rs create mode 100644 gcc/testsuite/rust/compile/torture/issue-893.rs create mode 100644 gcc/testsuite/rust/compile/torture/lazybooleanexpr_function.rs create mode 100644 gcc/testsuite/rust/compile/torture/lifetime1.rs create mode 100644 gcc/testsuite/rust/compile/torture/literals1.rs create mode 100644 gcc/testsuite/rust/compile/torture/loop1.rs create mode 100644 gcc/testsuite/rust/compile/torture/loop2.rs create mode 100644 gcc/testsuite/rust/compile/torture/loop3.rs create mode 100644 gcc/testsuite/rust/compile/torture/loop4.rs create mode 100644 gcc/testsuite/rust/compile/torture/loop5.rs create mode 100644 gcc/testsuite/rust/compile/torture/loop6.rs create mode 100644 gcc/testsuite/rust/compile/torture/loop7.rs create mode 100644 gcc/testsuite/rust/compile/torture/macro-issue1403.rs create mode 100644 gcc/testsuite/rust/compile/torture/macro-issue1426.rs create mode 100644 gcc/testsuite/rust/compile/torture/macro_as_expr.rs create mode 100644 gcc/testsuite/rust/compile/torture/match1.rs create mode 100644 gcc/testsuite/rust/compile/torture/methods1.rs create mode 100644 gcc/testsuite/rust/compile/torture/methods2.rs create mode 100644 gcc/testsuite/rust/compile/torture/methods3.rs create mode 100644 gcc/testsuite/rust/compile/torture/mod-nameresolve.rs create mode 100644 gcc/testsuite/rust/compile/torture/mod1.rs create mode 100644 gcc/testsuite/rust/compile/torture/mod2.rs create mode 100644 gcc/testsuite/rust/compile/torture/mod3.rs create mode 100644 gcc/testsuite/rust/compile/torture/modules/mod.rs create mode 100644 gcc/testsuite/rust/compile/torture/modules/valid_path.rs create mode 100644 gcc/testsuite/rust/compile/torture/must_use1.rs create mode 100644 gcc/testsuite/rust/compile/torture/must_use2.rs create mode 100644 gcc/testsuite/rust/compile/torture/name_resolve1.rs create mode 100644 gcc/testsuite/rust/compile/torture/negation_function.rs create mode 100644 gcc/testsuite/rust/compile/torture/nested_fn1.rs create mode 100644 gcc/testsuite/rust/compile/torture/nested_fn2.rs create mode 100644 gcc/testsuite/rust/compile/torture/nested_struct1.rs create mode 100644 gcc/testsuite/rust/compile/torture/never_type1.rs create mode 100644 gcc/testsuite/rust/compile/torture/not_shebang.rs create mode 100644 gcc/testsuite/rust/compile/torture/not_shebang_block_comment.rs create mode 100644 gcc/testsuite/rust/compile/torture/not_shebang_comment.rs create mode 100644 gcc/testsuite/rust/compile/torture/not_shebang_multiline_comment.rs create mode 100644 gcc/testsuite/rust/compile/torture/not_shebang_spaces.rs create mode 100644 gcc/testsuite/rust/compile/torture/parameter_usage1.rs create mode 100644 gcc/testsuite/rust/compile/torture/parens1.rs create mode 100644 gcc/testsuite/rust/compile/torture/pointer1.rs create mode 100644 gcc/testsuite/rust/compile/torture/primconsts.rs create mode 100644 gcc/testsuite/rust/compile/torture/prims_struct_eq.rs create mode 100644 gcc/testsuite/rust/compile/torture/range-lang-item1.rs create mode 100644 gcc/testsuite/rust/compile/torture/raw_identifiers.rs create mode 100644 gcc/testsuite/rust/compile/torture/raw_identifiers_keywords.rs create mode 100644 gcc/testsuite/rust/compile/torture/recursive_fn1.rs create mode 100644 gcc/testsuite/rust/compile/torture/return_function.rs create mode 100644 gcc/testsuite/rust/compile/torture/scoping1.rs create mode 100644 gcc/testsuite/rust/compile/torture/self_type1.rs create mode 100644 gcc/testsuite/rust/compile/torture/shadow1.rs create mode 100644 gcc/testsuite/rust/compile/torture/shadow2.rs create mode 100755 gcc/testsuite/rust/compile/torture/shebang.rs create mode 100755 gcc/testsuite/rust/compile/torture/shebang_plus_attr.rs create mode 100755 gcc/testsuite/rust/compile/torture/shebang_plus_attr2.rs create mode 100644 gcc/testsuite/rust/compile/torture/static_function.rs create mode 100644 gcc/testsuite/rust/compile/torture/static_var1.rs create mode 100644 gcc/testsuite/rust/compile/torture/stmt_with_block1.rs create mode 100644 gcc/testsuite/rust/compile/torture/str1.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_access1.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_base_init_1.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_decl.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init_10.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init_11.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init_2.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init_3.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init_4.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init_5.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init_6.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init_7.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init_8.rs create mode 100644 gcc/testsuite/rust/compile/torture/struct_init_9.rs create mode 100644 gcc/testsuite/rust/compile/torture/top_attr.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits1.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits10.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits11.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits12.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits13.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits14.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits15.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits16.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits17.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits18.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits19.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits2.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits3.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits4.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits5.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits6.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits7.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits8.rs create mode 100644 gcc/testsuite/rust/compile/torture/traits9.rs create mode 100644 gcc/testsuite/rust/compile/torture/transmute-size-check-1.rs create mode 100644 gcc/testsuite/rust/compile/torture/transmute1.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple1.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple2.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple3.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple_enum_variants.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple_field_access.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple_function.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple_index.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple_struct1.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple_struct2.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple_struct_unit.rs create mode 100644 gcc/testsuite/rust/compile/torture/tuple_struct_unused.rs create mode 100644 gcc/testsuite/rust/compile/torture/type-alias1.rs create mode 100644 gcc/testsuite/rust/compile/torture/type-alias2.rs create mode 100644 gcc/testsuite/rust/compile/torture/type_infer1.rs create mode 100644 gcc/testsuite/rust/compile/torture/type_infer2.rs create mode 100644 gcc/testsuite/rust/compile/torture/type_infer3.rs create mode 100644 gcc/testsuite/rust/compile/torture/type_infer4.rs create mode 100644 gcc/testsuite/rust/compile/torture/type_infer5.rs create mode 100644 gcc/testsuite/rust/compile/torture/type_infer6.rs create mode 100644 gcc/testsuite/rust/compile/torture/unary_operators.rs create mode 100644 gcc/testsuite/rust/compile/torture/undended-string-1.rs create mode 100644 gcc/testsuite/rust/compile/torture/undended-string-2.rs create mode 100644 gcc/testsuite/rust/compile/torture/underscore_id.rs create mode 100644 gcc/testsuite/rust/compile/torture/union.rs create mode 100644 gcc/testsuite/rust/compile/torture/union_union.rs create mode 100644 gcc/testsuite/rust/compile/torture/unit_type1.rs create mode 100644 gcc/testsuite/rust/compile/torture/unit_type2.rs create mode 100644 gcc/testsuite/rust/compile/torture/unit_type3.rs create mode 100644 gcc/testsuite/rust/compile/torture/unit_type4.rs create mode 100644 gcc/testsuite/rust/compile/torture/unit_type5.rs create mode 100644 gcc/testsuite/rust/compile/torture/unsafe1.rs create mode 100644 gcc/testsuite/rust/compile/torture/unsafe2.rs create mode 100644 gcc/testsuite/rust/compile/torture/unsafe3.rs create mode 100644 gcc/testsuite/rust/compile/torture/unsafe4.rs create mode 100644 gcc/testsuite/rust/compile/torture/unused.rs create mode 100644 gcc/testsuite/rust/compile/torture/unused1.rs create mode 100644 gcc/testsuite/rust/compile/torture/unused_struct.rs create mode 100644 gcc/testsuite/rust/compile/torture/unused_struct_field.rs create mode 100644 gcc/testsuite/rust/compile/torture/usize1.rs create mode 100644 gcc/testsuite/rust/compile/torture/very-broken-attr-string.rs create mode 100644 gcc/testsuite/rust/compile/torture/while_function.rs create mode 100644 gcc/testsuite/rust/compile/traits1.rs create mode 100644 gcc/testsuite/rust/compile/traits10.rs create mode 100644 gcc/testsuite/rust/compile/traits11.rs create mode 100644 gcc/testsuite/rust/compile/traits12.rs create mode 100644 gcc/testsuite/rust/compile/traits2.rs create mode 100644 gcc/testsuite/rust/compile/traits3.rs create mode 100644 gcc/testsuite/rust/compile/traits4.rs create mode 100644 gcc/testsuite/rust/compile/traits5.rs create mode 100644 gcc/testsuite/rust/compile/traits6.rs create mode 100644 gcc/testsuite/rust/compile/traits7.rs create mode 100644 gcc/testsuite/rust/compile/traits8.rs create mode 100644 gcc/testsuite/rust/compile/traits9.rs create mode 100644 gcc/testsuite/rust/compile/tuple1.rs create mode 100644 gcc/testsuite/rust/compile/tuple_struct1.rs create mode 100644 gcc/testsuite/rust/compile/tuple_struct2.rs create mode 100644 gcc/testsuite/rust/compile/tuple_struct3.rs create mode 100644 gcc/testsuite/rust/compile/type-alias1.rs create mode 100644 gcc/testsuite/rust/compile/type-bindings1.rs create mode 100644 gcc/testsuite/rust/compile/unary_negation.rs create mode 100644 gcc/testsuite/rust/compile/unary_not.rs create mode 100644 gcc/testsuite/rust/compile/unconstrained_type_param.rs create mode 100644 gcc/testsuite/rust/compile/unicode_escape.rs create mode 100644 gcc/testsuite/rust/compile/unsafe1.rs create mode 100644 gcc/testsuite/rust/compile/unsafe10.rs create mode 100644 gcc/testsuite/rust/compile/unsafe2.rs create mode 100644 gcc/testsuite/rust/compile/unsafe3.rs create mode 100644 gcc/testsuite/rust/compile/unsafe4.rs create mode 100644 gcc/testsuite/rust/compile/unsafe5.rs create mode 100644 gcc/testsuite/rust/compile/unsafe6.rs create mode 100644 gcc/testsuite/rust/compile/unsafe7.rs create mode 100644 gcc/testsuite/rust/compile/unsafe8.rs create mode 100644 gcc/testsuite/rust/compile/unsafe9.rs create mode 100644 gcc/testsuite/rust/compile/unterminated_c_comment.rs create mode 100644 gcc/testsuite/rust/compile/use_1.rs create mode 100644 gcc/testsuite/rust/compile/usize1.rs create mode 100644 gcc/testsuite/rust/compile/xfail/lifetime_param.rs create mode 100644 gcc/testsuite/rust/compile/xfail/struct_field_vis.rs create mode 100644 gcc/testsuite/rust/compile/xfail/xfail.exp new file mode 100644 index 00000000000..ae51e36c87f diff --git a/gcc/testsuite/rust/compile/abi-options1.rs b/gcc/testsuite/rust/compile/abi-options1.rs new file mode 100644 index 00000000000..a4b6241dc15 --- /dev/null +++ b/gcc/testsuite/rust/compile/abi-options1.rs @@ -0,0 +1,7 @@ +extern "foobar" { + // { dg-error "unknown ABI option" "" { target *-*-* } .-1 } + fn printf(s: *const i8, ...); +} + +pub extern "baz" fn test() {} +// { dg-error "unknown ABI option" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/array3.rs b/gcc/testsuite/rust/compile/array3.rs new file mode 100644 index 00000000000..a56be9a0e8b --- /dev/null +++ b/gcc/testsuite/rust/compile/array3.rs @@ -0,0 +1,4 @@ +fn foo(state: &mut [u32; 16], a: usize) { + // { dg-warning "function is never used: .foo." "" { target *-*-* } .-1 } + state[a] = 1; +} diff --git a/gcc/testsuite/rust/compile/array_empty_list.rs b/gcc/testsuite/rust/compile/array_empty_list.rs new file mode 100644 index 00000000000..76e082a6d57 --- /dev/null +++ b/gcc/testsuite/rust/compile/array_empty_list.rs @@ -0,0 +1,4 @@ +fn main() { + let arr = []; + // { dg-error "type annotations needed" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/arrays1.rs b/gcc/testsuite/rust/compile/arrays1.rs new file mode 100644 index 00000000000..714a6be7afb --- /dev/null +++ b/gcc/testsuite/rust/compile/arrays1.rs @@ -0,0 +1,4 @@ +fn main() { + let xs: [i32; 5] = [1, 2, 3, 4, 5]; + let a: bool = xs[0]; // { dg-error "expected .bool. got .i32." } +} diff --git a/gcc/testsuite/rust/compile/arrays2.rs b/gcc/testsuite/rust/compile/arrays2.rs new file mode 100644 index 00000000000..c96f4f7d820 --- /dev/null +++ b/gcc/testsuite/rust/compile/arrays2.rs @@ -0,0 +1,5 @@ +// { dg-additional-options "-w" } +fn main() { + let array: [i32; 5] = [1, 2, 3]; + // { dg-error "expected an array with a fixed size of 5 elements, found one with 3 elements" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/attr-mismatch-crate-name.rs b/gcc/testsuite/rust/compile/attr-mismatch-crate-name.rs new file mode 100644 index 00000000000..1d406031fee --- /dev/null +++ b/gcc/testsuite/rust/compile/attr-mismatch-crate-name.rs @@ -0,0 +1,4 @@ +// { dg-additional-options "-fdump-tree-gimple" } +#![crate_name = "specified_name"] +// { dg-final { scan-tree-dump-times {specified_name::main} 1 gimple } } +fn main() {} diff --git a/gcc/testsuite/rust/compile/attr_cold.rs b/gcc/testsuite/rust/compile/attr_cold.rs new file mode 100644 index 00000000000..f705ea9b2ff --- /dev/null +++ b/gcc/testsuite/rust/compile/attr_cold.rs @@ -0,0 +1,12 @@ +// { dg-additional-options "-fdump-tree-gimple" } +#[cold] +fn cold_function() -> i32 { + 42 +} + +fn main() -> i32 { + // { dg-final { scan-tree-dump-times {__attribute__\(\(cdecl, cold\)\)} 1 gimple } } + cold_function(); + + 0 +} diff --git a/gcc/testsuite/rust/compile/attr_deprecated.rs b/gcc/testsuite/rust/compile/attr_deprecated.rs new file mode 100644 index 00000000000..01bc9c41502 --- /dev/null +++ b/gcc/testsuite/rust/compile/attr_deprecated.rs @@ -0,0 +1,14 @@ +#[deprecated(since="1.0", note="do not use this function")] +fn test1() {} + +#[deprecated] +fn test() {} + +#[deprecated = "a different message"] +fn test2() {} + +fn main() { + test(); // { dg-warning ".attr_deprecated::test. is deprecated" } + test1(); // { dg-warning ".attr_deprecated::test1. is deprecated: do not use this function" } + test2(); // { dg-warning ".attr_deprecated::test2. is deprecated: a different message" } +} diff --git a/gcc/testsuite/rust/compile/attr_deprecated_2.rs b/gcc/testsuite/rust/compile/attr_deprecated_2.rs new file mode 100644 index 00000000000..66f4ce3b076 --- /dev/null +++ b/gcc/testsuite/rust/compile/attr_deprecated_2.rs @@ -0,0 +1,11 @@ +#[deprecated(since="1.0")] +fn test1() {} + +// { dg-excess-errors "unknown meta item ...." } +#[deprecated(invalid="invalid")] +fn test2() {} + +fn main() { + test1(); // { dg-warning ".attr_deprecated_2::test1. is deprecated" } + test2(); +} diff --git a/gcc/testsuite/rust/compile/bad-crate-name.rs b/gcc/testsuite/rust/compile/bad-crate-name.rs new file mode 100644 index 00000000000..6c59c255cc2 --- /dev/null +++ b/gcc/testsuite/rust/compile/bad-crate-name.rs @@ -0,0 +1,4 @@ +// { dg-additional-options "-frust-crate=bad+name" } +// { dg-excess-errors "invalid crate name: ...." } +// { dg-excess-errors "unrecognized command-line option ...." } +fn main() {} diff --git a/gcc/testsuite/rust/compile/bad=file-name.rs b/gcc/testsuite/rust/compile/bad=file-name.rs new file mode 100644 index 00000000000..cfbebb0698d --- /dev/null +++ b/gcc/testsuite/rust/compile/bad=file-name.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-fdump-tree-gimple -frust-crate=good_name" } +pub fn does_nothing() {} +fn main() { + does_nothing() +} +// { dg-final { scan-tree-dump-times {good_name::does_nothing} 2 gimple } } +// { dg-final { scan-tree-dump-times {good_name::main} 1 gimple } } diff --git a/gcc/testsuite/rust/compile/bad_as_bool_char.rs b/gcc/testsuite/rust/compile/bad_as_bool_char.rs new file mode 100644 index 00000000000..91a28eebe00 --- /dev/null +++ b/gcc/testsuite/rust/compile/bad_as_bool_char.rs @@ -0,0 +1,18 @@ +pub fn main () +{ + let t = true; + let f = false; + let fone = t as f32; // { dg-error "invalid cast" } + let fzero = f as f64; // { dg-error "invalid cast" } + + let nb = 0u8 as bool; // { dg-error "invalid cast" } + let nc = true as char; // { dg-error "invalid cast" } + + let a = 'a'; + let b = 'b'; + let fa = a as f32; // { dg-error "invalid cast" } + let bb = b as bool; // { dg-error "invalid cast" } + + let t32: u32 = 33; + let ab = t32 as char; // { dg-error "invalid cast" } +} diff --git a/gcc/testsuite/rust/compile/bad_file_name.txt.rs b/gcc/testsuite/rust/compile/bad_file_name.txt.rs new file mode 100644 index 00000000000..56e2093b27c --- /dev/null +++ b/gcc/testsuite/rust/compile/bad_file_name.txt.rs @@ -0,0 +1,3 @@ +// { dg-excess-errors "invalid crate name: ...." } +// { dg-bogus "unrecognized command-line option ...." } +fn main() {} diff --git a/gcc/testsuite/rust/compile/bad_inner_doc.rs b/gcc/testsuite/rust/compile/bad_inner_doc.rs new file mode 100644 index 00000000000..cfd166ce3ec --- /dev/null +++ b/gcc/testsuite/rust/compile/bad_inner_doc.rs @@ -0,0 +1,15 @@ +pub fn main () +{ + //! inner doc allowed + let _x = 42; + // { dg-error "inner doc" "" { target *-*-* } .+1 } + //! inner doc disallowed + mod module + { + /*! inner doc allowed */ + /// outer doc allowed + // { dg-error "inner doc" "" { target *-*-* } .+1 } + /*! but inner doc not here */ + mod x { } + } +} diff --git a/gcc/testsuite/rust/compile/bad_pub_enumitems.rs b/gcc/testsuite/rust/compile/bad_pub_enumitems.rs new file mode 100644 index 00000000000..e7fd5edb981 --- /dev/null +++ b/gcc/testsuite/rust/compile/bad_pub_enumitems.rs @@ -0,0 +1,47 @@ +pub enum E +{ + pub A { a: i32 }, // { dg-error "visibility qualifier" } + B (u8), + pub C, // { dg-error "visibility qualifier" } + D +} + +enum E1 +{ + A, + pub B = 42, // { dg-error "visibility qualifier" } + C = 3, + D, + pub E // { dg-error "visibility qualifier" } +} + +enum E2 +{ + pub A (u8, i32, u64), // { dg-error "visibility qualifier" } + B { a: u8, a: u8 } // { dg-error "duplicate field" }} +} + +fn main () +{ + enum EE + { + Alpha { alpha: i32 }, + pub Beta (u8), // { dg-error "visibility qualifier" } + pub Gamma, // { dg-error "visibility qualifier" } + Delta { delta: u32 } + } + + enum EE1 + { + pub Alpha, // { dg-error "visibility qualifier" } + Beta = 41, + pub Gamma = 3, // { dg-error "visibility qualifier" } + Delta, + } + + enum E2 + { + Alpha { a: u8, a: u8 }, // { dg-error "duplicate field" }} + pub Beta (u8, i32, u64) // { dg-error "visibility qualifier" } + } +} diff --git a/gcc/testsuite/rust/compile/bad_stmt_enums.rs b/gcc/testsuite/rust/compile/bad_stmt_enums.rs new file mode 100644 index 00000000000..7b09a94fd27 --- /dev/null +++ b/gcc/testsuite/rust/compile/bad_stmt_enums.rs @@ -0,0 +1,22 @@ +fn main () +{ + enum EE + { + Alpha { alpha: i32 }, + pub Beta (u8), + pub Gamma, + Gamma { gamma: u32 } // { dg-error "redefined" } + } + + struct EE2 { } + enum EE2 { } // { dg-error "redefined" } + + enum EE1 + { + pub Alpha, + Beta = 41, + Beta = 42, // { dg-error "redefined" } + pub Gamma = 3, + D, + } +} diff --git a/gcc/testsuite/rust/compile/bad_toplevel_enums.rs b/gcc/testsuite/rust/compile/bad_toplevel_enums.rs new file mode 100644 index 00000000000..b655e30a93d --- /dev/null +++ b/gcc/testsuite/rust/compile/bad_toplevel_enums.rs @@ -0,0 +1,19 @@ +pub enum E +{ + pub A { a: i32 }, + B (u8), + pub C, + B // { dg-error "redefined" } +} + +enum E2 { } +struct E2 { } // { dg-error "redefined" } + +enum E1 +{ + A, + pub B = 42, + C = 3, + A { a: u8 }, // { dg-error "redefined" } + pub D +} diff --git a/gcc/testsuite/rust/compile/bad_tuple_index.rs b/gcc/testsuite/rust/compile/bad_tuple_index.rs new file mode 100644 index 00000000000..c3bd1e91d10 --- /dev/null +++ b/gcc/testsuite/rust/compile/bad_tuple_index.rs @@ -0,0 +1,66 @@ +fn main() +{ + // tuples + let z = (); + + let o = (0,); + /* Binary, Octal and Hex literals are invalid. */ + let _fb = o.0b0; // { dg-error "tuple index should be a pure decimal literal" } + let _fo = o.0o0; // { dg-error "tuple index should be a pure decimal literal" } + let _fh = o.0x0; // { dg-error "tuple index should be a pure decimal literal" } + + /* No underscores. */ + let _fua = o.0_; // { dg-error "tuple index should be a pure decimal literal" } + + /* Suffix is not allowed. */ + let _fu8 = o.0u8; // { dg-error "tuple index should be a pure decimal literal" } + let _fi8 = o.0i8; // { dg-error "tuple index should be a pure decimal literal" } + let _fu16 = o.0u16; // { dg-error "tuple index should be a pure decimal literal" } + let _fi16 = o.0i16; // { dg-error "tuple index should be a pure decimal literal" } + let _fu32 = o.0u32; // { dg-error "tuple index should be a pure decimal literal" } + let _fi32 = o.0i32; // { dg-error "tuple index should be a pure decimal literal" } + let _fu64 = o.0u64; // { dg-error "tuple index should be a pure decimal literal" } + let _fi64 = o.0i64; // { dg-error "tuple index should be a pure decimal literal" } + let _fu128 = o.0u128; // { dg-error "tuple index should be a pure decimal literal" } + let _fi128 = o.0i128; // { dg-error "tuple index should be a pure decimal literal" } + let _fusize = o.0usize; // { dg-error "tuple index should be a pure decimal literal" } + let _fisize = o.0isize; // { dg-error "tuple index should be a pure decimal literal" } + + let t = (0,1); + /* No extra zero prefix. */ + let _s = t.01; // { dg-error "tuple index should be a pure decimal literal" } + + let m = (0,1,2,3,4,5,6,7,8,9,10); + /* No extra zero prefix. */ + let _l = m.010; // { dg-error "tuple index should be a pure decimal literal" } + + /* No underscores. */ + let _lu = m.1_0; // { dg-error "tuple index should be a pure decimal literal" } + + // tuple structs + struct E(); + let _e = E(); + + struct O(i32); + let so = O(0); + /* No leading zeros, no underscores. */ + let _sf = so.0_0; // { dg-error "tuple index should be a pure decimal literal" } + /* Binary, Octal and Hex literals are invalid. */ + let _sb = so.0b0; // { dg-error "tuple index should be a pure decimal literal" } + let _so = so.0o0; // { dg-error "tuple index should be a pure decimal literal" } + let _sh = so.0x0; // { dg-error "tuple index should be a pure decimal literal" } + + struct T(i32,i32); + let st = T(0,1); + /* Suffix is not allowed. */ + let _stfu32 = st.1u32; // { dg-error "tuple index should be a pure decimal literal" } + let _stfi32 = st.1i32; // { dg-error "tuple index should be a pure decimal literal" } + + struct M(i32,i32,i32,i32,i32,i32,i32,i32,i32,i32,i32); + let sm = M(0,1,2,3,4,5,6,7,8,9,10); + /* No underscores. */ + let _sl2 = sm.1_0; // { dg-error "tuple index should be a pure decimal literal" } + let _sl3 = sm.10_; // { dg-error "tuple index should be a pure decimal literal" } + + z +} diff --git a/gcc/testsuite/rust/compile/bad_type1.rs b/gcc/testsuite/rust/compile/bad_type1.rs new file mode 100644 index 00000000000..93de439704f --- /dev/null +++ b/gcc/testsuite/rust/compile/bad_type1.rs @@ -0,0 +1,3 @@ +fn main() { + let logical: bool = 123; // { dg-error "expected .bool. got .." } +} diff --git a/gcc/testsuite/rust/compile/bad_type2.rs b/gcc/testsuite/rust/compile/bad_type2.rs new file mode 100644 index 00000000000..e47b8aac0e7 --- /dev/null +++ b/gcc/testsuite/rust/compile/bad_type2.rs @@ -0,0 +1,14 @@ +fn test(x: i32) -> i32 { + return x + 1; +} + +fn main() { + let mut an_integer = 5; + an_integer = test(1) + 3; + + let mut x; + x = 1; + x = true; // { dg-error "expected .. got .bool." } + + let call_test = test(1); +} diff --git a/gcc/testsuite/rust/compile/break1.rs b/gcc/testsuite/rust/compile/break1.rs new file mode 100644 index 00000000000..91cabffa894 --- /dev/null +++ b/gcc/testsuite/rust/compile/break1.rs @@ -0,0 +1,6 @@ +fn main() { + let a; + a = 1; + break a; // { dg-error "cannot 'break' outside of a loop" } + // { dg-error "failed to type resolve expression" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/break2.rs b/gcc/testsuite/rust/compile/break2.rs new file mode 100644 index 00000000000..5ac806aeb9e --- /dev/null +++ b/gcc/testsuite/rust/compile/break2.rs @@ -0,0 +1,15 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + let mut c; + while b > 10 { + if (b == 2) { + break b; // { dg-error "can only break with a value inside 'loop'" } + // { dg-error "failed to type resolve expression" "" { target *-*-* } .-1 } + } + c = a + b; + a = b; + b = c; + } +} diff --git a/gcc/testsuite/rust/compile/builtin_macro_compile_error.rs b/gcc/testsuite/rust/compile/builtin_macro_compile_error.rs new file mode 100644 index 00000000000..9d224406a3e --- /dev/null +++ b/gcc/testsuite/rust/compile/builtin_macro_compile_error.rs @@ -0,0 +1,13 @@ +#[rustc_builtin_macro] +macro_rules! compile_error { + () => {{}}; +} + +fn main () { + let message = "error message"; + compile_error! (message); // { dg-error "argument must be a string literal" "" } + compile_error! (); // { dg-error "macro takes 1 argument" "" } + compile_error! ("a", "b"); // { dg-error "macro takes 1 argument" "" } + compile_error! ("expected error message"); // { dg-error "expected error message" } + compile_error! ("expected error message",); // { dg-error "expected error message" } +} diff --git a/gcc/testsuite/rust/compile/builtin_macro_concat.rs b/gcc/testsuite/rust/compile/builtin_macro_concat.rs new file mode 100644 index 00000000000..9b878af764d --- /dev/null +++ b/gcc/testsuite/rust/compile/builtin_macro_concat.rs @@ -0,0 +1,17 @@ +#[rustc_builtin_macro] +macro_rules! concat { + () => {{}}; +} + +fn main() { + let not_literal = "identifier"; + concat!(); + concat! (,); // { dg-error "argument must be a constant literal" } + concat!(not_literal); // { dg-error "argument must be a constant literal" } + concat!("message"); + concat!("message",); + concat!("message", 1, true, false, 1.0, 10usize, 2000u64); + concat!("message", 1, true, false, 1.0, 10usize, 2000u64,); + concat! ("m", not_literal); // { dg-error "argument must be a constant literal" } + concat!(not_literal invalid 'm' !!,); // { dg-error "argument must be a constant literal" } +} diff --git a/gcc/testsuite/rust/compile/builtin_macro_env.rs b/gcc/testsuite/rust/compile/builtin_macro_env.rs new file mode 100644 index 00000000000..289e6db2cf1 --- /dev/null +++ b/gcc/testsuite/rust/compile/builtin_macro_env.rs @@ -0,0 +1,20 @@ +#[rustc_builtin_macro] +macro_rules! env { + () => {{}}; +} + +fn main () { + let message = "error message"; + env! (message); // { dg-error "argument must be a string literal" "" } + env! (); // { dg-error "env! takes 1 or 2 arguments" "" } + env! (,); // { dg-error "argument must be a string literal" "" } + env! (1); // { dg-error "argument must be a string literal" "" } + env! ("NOT_DEFINED"); // { dg-error "environment variable 'NOT_DEFINED' not defined" "" } + env! ("NOT_DEFINED",); // { dg-error "environment variable 'NOT_DEFINED' not defined" "" } + env! ("NOT_DEFINED", 1); // { dg-error "argument must be a string literal" "" } + env! ("NOT_DEFINED", "two", "three"); // { dg-error "env! takes 1 or 2 arguments" "" } + env! ("NOT_DEFINED" "expected error message"); // { dg-error "expected token: ','" "" } + env! ("NOT_DEFINED", "expected error message"); // { dg-error "expected error message" "" } + env! ("NOT_DEFINED", "expected error message",); // { dg-error "expected error message" "" } + env! (1, "two"); // { dg-error "argument must be a string literal" "" } +} diff --git a/gcc/testsuite/rust/compile/builtin_macro_include_bytes.rs b/gcc/testsuite/rust/compile/builtin_macro_include_bytes.rs new file mode 100644 index 00000000000..38716d33bcd --- /dev/null +++ b/gcc/testsuite/rust/compile/builtin_macro_include_bytes.rs @@ -0,0 +1,13 @@ +#[rustc_builtin_macro] +macro_rules! include_bytes { + () => {{}}; +} + +fn main () { + let file = "include.txt"; + include_bytes! (file); // { dg-error "argument must be a string literal" "" } + include_bytes! (); // { dg-error "macro takes 1 argument" "" } + include_bytes! ("foo.txt", "bar.txt"); // { dg-error "macro takes 1 argument" "" } + include_bytes! ("builtin_macro_include_bytes.rs"); // ok + include_bytes! ("builtin_macro_include_bytes.rs",); // trailing comma ok +} diff --git a/gcc/testsuite/rust/compile/builtin_macro_include_str.rs b/gcc/testsuite/rust/compile/builtin_macro_include_str.rs new file mode 100644 index 00000000000..38f5e3b7334 --- /dev/null +++ b/gcc/testsuite/rust/compile/builtin_macro_include_str.rs @@ -0,0 +1,13 @@ +#[rustc_builtin_macro] +macro_rules! include_str { + () => {{}}; +} + +fn main () { + let file = "include.txt"; + include_str! (file); // { dg-error "argument must be a string literal" "" } + include_str! (); // { dg-error "macro takes 1 argument" "" } + include_str! ("foo.txt", "bar.txt"); // { dg-error "macro takes 1 argument" "" } + include_str! ("builtin_macro_include_str.rs"); // ok + include_str! ("builtin_macro_include_str.rs",); // trailing comma ok +} diff --git a/gcc/testsuite/rust/compile/builtin_macro_not_found.rs b/gcc/testsuite/rust/compile/builtin_macro_not_found.rs new file mode 100644 index 00000000000..1a3228b9284 --- /dev/null +++ b/gcc/testsuite/rust/compile/builtin_macro_not_found.rs @@ -0,0 +1,4 @@ +#[rustc_builtin_macro] +macro_rules! crabby_crab_carb { // { dg-error "cannot find a built-in macro with name .crabby_crab_carb." } + () => {{}}; +} diff --git a/gcc/testsuite/rust/compile/bytecharstring.rs b/gcc/testsuite/rust/compile/bytecharstring.rs new file mode 100644 index 00000000000..9242e2c5a0b --- /dev/null +++ b/gcc/testsuite/rust/compile/bytecharstring.rs @@ -0,0 +1,8 @@ +fn main () +{ + let _bc = b'\x80'; + let _bs = b"foo\x80bar"; + + let _c = '\xef'; // { dg-error "out of range" } + let _s = "Foo\xEFBar"; // { dg-error "out of range" } +} diff --git a/gcc/testsuite/rust/compile/canonical_paths1.rs b/gcc/testsuite/rust/compile/canonical_paths1.rs new file mode 100644 index 00000000000..193e7b5b698 --- /dev/null +++ b/gcc/testsuite/rust/compile/canonical_paths1.rs @@ -0,0 +1,25 @@ +// { dg-additional-options "-w -fdump-tree-gimple -frust-crate=example" } +struct Foo(i32); + +trait TR { + fn test(&self) -> i32; +} + +mod A { + impl ::Foo { + pub fn test(self) {} + // { dg-final { scan-tree-dump-times {example::A::::test} 2 gimple } } + } + + impl ::TR for ::Foo { + fn test(&self) -> i32 { + // { dg-final { scan-tree-dump-times {example::A::::test} 1 gimple } } + self.0 + } + } +} + +pub fn test() { + let a = Foo(123); + a.test(); +} diff --git a/gcc/testsuite/rust/compile/cast1.rs b/gcc/testsuite/rust/compile/cast1.rs new file mode 100644 index 00000000000..74c4b1eaac4 --- /dev/null +++ b/gcc/testsuite/rust/compile/cast1.rs @@ -0,0 +1,5 @@ +fn main() { + let a: i32 = 123; + let b = a as char; + // { dg-error "invalid cast .i32. to .char." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/cfg1.rs b/gcc/testsuite/rust/compile/cfg1.rs new file mode 100644 index 00000000000..6984f04d1b9 --- /dev/null +++ b/gcc/testsuite/rust/compile/cfg1.rs @@ -0,0 +1,31 @@ +// { dg-additional-options "-w" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[cfg(A)] +fn test() { + unsafe { + let a = "test1\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } +} + +#[cfg(B)] +fn test() { + unsafe { + let a = "test2\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } +} + +fn main() { + test(); + // { dg-error "Cannot find path .test. in this scope" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/cfg2.rs b/gcc/testsuite/rust/compile/cfg2.rs new file mode 100644 index 00000000000..939384c5b7d --- /dev/null +++ b/gcc/testsuite/rust/compile/cfg2.rs @@ -0,0 +1,13 @@ +// { dg-additional-options "-w -frust-cfg=A" } +struct Foo; +impl Foo { + #[cfg(not(A))] + fn test(&self) {} +} + +fn main() { + let a = Foo; + a.test(); + // { dg-error "failed to resolve method for .test." "" { target *-*-* } .-1 } + // { dg-error "failed to type resolve expression" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/cfg3.rs b/gcc/testsuite/rust/compile/cfg3.rs new file mode 100644 index 00000000000..d6ffab6bfc6 --- /dev/null +++ b/gcc/testsuite/rust/compile/cfg3.rs @@ -0,0 +1,11 @@ +// { dg-additional-options "-w -frust-cfg=A -frust-cfg=B" } +struct Foo; +impl Foo { + #[cfg(all(A, B))] + fn test(&self) {} +} + +fn main() { + let a = Foo; + a.test(); +} diff --git a/gcc/testsuite/rust/compile/cfg4.rs b/gcc/testsuite/rust/compile/cfg4.rs new file mode 100644 index 00000000000..2834c277ddf --- /dev/null +++ b/gcc/testsuite/rust/compile/cfg4.rs @@ -0,0 +1,11 @@ +// { dg-additional-options "-w -frust-cfg=A" } +struct Foo; +impl Foo { + #[cfg(any(A, B))] + fn test(&self) {} +} + +fn main() { + let a = Foo; + a.test(); +} diff --git a/gcc/testsuite/rust/compile/cfg5.rs b/gcc/testsuite/rust/compile/cfg5.rs new file mode 100644 index 00000000000..1852efaf8df --- /dev/null +++ b/gcc/testsuite/rust/compile/cfg5.rs @@ -0,0 +1,11 @@ +// { dg-additional-options "-w -frust-cfg=A=\"B\"" } +struct Foo; +impl Foo { + #[cfg(A = "B")] + fn test(&self) {} +} + +fn main() { + let a = Foo; + a.test(); +} diff --git a/gcc/testsuite/rust/compile/compile.exp b/gcc/testsuite/rust/compile/compile.exp new file mode 100644 index 00000000000..13423d76c92 --- /dev/null +++ b/gcc/testsuite/rust/compile/compile.exp @@ -0,0 +1,35 @@ +# Copyright (C) 2021-2022 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 +# . + +# Compile tests, no torture testing. +# +# These tests raise errors in the front end; torture testing doesn't apply. + +# Load support procs. +load_lib rust-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +set saved-dg-do-what-default ${dg-do-what-default} + +set dg-do-what-default "compile" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" "" +set dg-do-what-default ${saved-dg-do-what-default} + +# All done. +dg-finish diff --git a/gcc/testsuite/rust/compile/complex-path1.rs b/gcc/testsuite/rust/compile/complex-path1.rs new file mode 100644 index 00000000000..54011bd6976 --- /dev/null +++ b/gcc/testsuite/rust/compile/complex-path1.rs @@ -0,0 +1,18 @@ +// { dg-additional-options "-w" } +mod a { + pub fn foo() {} +} + +mod b { + pub fn foo() { + super::a::foo(); + } +} + +mod foo { + pub struct bar(pub i32); +} + +fn test() -> crate::foo::bar { + foo::bar(123) +} diff --git a/gcc/testsuite/rust/compile/const-issue1440.rs b/gcc/testsuite/rust/compile/const-issue1440.rs new file mode 100644 index 00000000000..9b974b96bbb --- /dev/null +++ b/gcc/testsuite/rust/compile/const-issue1440.rs @@ -0,0 +1,76 @@ +// { dg-additional-options "-w" } + +mod intrinsics { + extern "rust-intrinsic" { + pub fn wrapping_add(a: T, b: T) -> T; + pub fn rotate_left(a: T, b: T) -> T; + pub fn rotate_right(a: T, b: T) -> T; + pub fn offset(ptr: *const T, count: isize) -> *const T; + } +} + +mod mem { + extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_transmute", since = "1.46.0")] + pub fn transmute(_: T) -> U; + pub fn size_of() -> usize; + } +} + +macro_rules! impl_uint { + ($($ty:ident = $lang:literal),*) => { + $( + impl $ty { + pub fn wrapping_add(self, rhs: Self) -> Self { + // intrinsics::wrapping_add(self, rhs) + self + rhs + } + + pub fn rotate_left(self, n: u32) -> Self { + unsafe { + intrinsics::rotate_left(self, n as Self) + } + } + + pub fn rotate_right(self, n: u32) -> Self { + unsafe { + intrinsics::rotate_right(self, n as Self) + } + } + + pub fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + } + + pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { + // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" "" { target *-*-* } .-1 } + Self::from_le(Self::from_ne_bytes(bytes)) + } + + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + } + + pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" "" { target *-*-* } .-1 } + unsafe { mem::transmute(bytes) } + } + } + )* + } +} + +impl_uint!( + u8 = "u8", + u16 = "u16", + u32 = "u32", + u64 = "u64", + u128 = "u128", + usize = "usize" +); diff --git a/gcc/testsuite/rust/compile/const1.rs b/gcc/testsuite/rust/compile/const1.rs new file mode 100644 index 00000000000..5f19c674c94 --- /dev/null +++ b/gcc/testsuite/rust/compile/const1.rs @@ -0,0 +1,6 @@ +fn bar() {} + +const fn foo() { + bar(); // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" } +} + diff --git a/gcc/testsuite/rust/compile/const2.rs b/gcc/testsuite/rust/compile/const2.rs new file mode 100644 index 00000000000..17b6de573dd --- /dev/null +++ b/gcc/testsuite/rust/compile/const2.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-w" } + +const fn foo() { + const fn bar() {} + + bar(); +} diff --git a/gcc/testsuite/rust/compile/const3.rs b/gcc/testsuite/rust/compile/const3.rs new file mode 100644 index 00000000000..22dc3d356ca --- /dev/null +++ b/gcc/testsuite/rust/compile/const3.rs @@ -0,0 +1,7 @@ +fn size() -> usize { + 15 +} + +fn main() { + let a = [15; size()]; // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" } +} diff --git a/gcc/testsuite/rust/compile/const_generics_1.rs b/gcc/testsuite/rust/compile/const_generics_1.rs new file mode 100644 index 00000000000..bcad8ee6a19 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_1.rs @@ -0,0 +1,19 @@ +// { dg-additional-options "-w" } + +// There are errors about unused generic parameters, but we can't handle that yet. +// Still, this code is invalid Rust. + +mod sain { + struct Foo; + struct Bar; + struct Baz<'l, T, const N: usize>; +} + +mod doux { + struct Foo; + struct Bar; + + const N_DEFAULT: usize = 3; + + struct Baz<'l, T, const N: usize = N_DEFAULT>; +} diff --git a/gcc/testsuite/rust/compile/const_generics_2.rs b/gcc/testsuite/rust/compile/const_generics_2.rs new file mode 100644 index 00000000000..98495cf404d --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_2.rs @@ -0,0 +1,4 @@ +struct Foo; // { dg-error "expecting .:. but .>. found" } +struct Bar; // { dg-error "unrecognised token .>. in type" } +struct Baz; // { dg-error "invalid token for start of default value for const generic parameter" } +// { dg-error "unrecognised token .>. in type" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/const_generics_3.rs b/gcc/testsuite/rust/compile/const_generics_3.rs new file mode 100644 index 00000000000..6a3a0fe27bf --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_3.rs @@ -0,0 +1,26 @@ +// { dg-additional-options "-w" } + +const M: usize = 4; + +struct Foo { + // FIXME: This error is bogus. But having it means parsing is valid! + value: [i32; N], // { dg-error "failed to find name: N" } +} + +fn main() { + let foo = Foo:: { value: [15] }; + let foo = Foo:: { value: [15, 13] }; + let foo: Foo = Foo { value: [15, 13] }; + let foo: Foo = Foo:: { value: [15, 13] }; + let foo: Foo = Foo { value: [15, 13] }; + let foo = Foo:: { value: [15, 13] }; + let foo: Foo = Foo:: { value: [15, 13] }; + let foo: Foo = Foo:: { + value: [15, 13, 11, 9], + }; + + // FIXME: Add proper const typecheck errors here + let invalid_foo: Foo = Foo:: { value: [15, 13] }; + let invalid_foo: Foo = Foo:: { value: [15, 13] }; + let invalid_foo: Foo = Foo:: { value: [15, 13] }; +} diff --git a/gcc/testsuite/rust/compile/const_generics_4.rs b/gcc/testsuite/rust/compile/const_generics_4.rs new file mode 100644 index 00000000000..8a3754da433 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_4.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-w" } + +const P: usize = 14; + +struct Foo; // { dg-error "failed to find name: M" } +struct Bar; +struct Baz; // { dg-error "failed to resolve TypePath: NotAType in this scope" } diff --git a/gcc/testsuite/rust/compile/const_generics_5.rs b/gcc/testsuite/rust/compile/const_generics_5.rs new file mode 100644 index 00000000000..5344e31a140 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_5.rs @@ -0,0 +1,12 @@ +struct Foo; + +const M: usize = 15; +type N = Foo<3>; + +fn main() { + let _: Foo<15> = Foo; + let _: Foo<{ M }> = Foo; + let _: Foo = Foo; + // bogus error, but it means the above const generic gets disambiguated properly + let _: Foo = Foo; // { dg-error "TypePath Foo declares generic arguments but the type Foo{Foo {}} does not have any" } +} diff --git a/gcc/testsuite/rust/compile/const_generics_6.rs b/gcc/testsuite/rust/compile/const_generics_6.rs new file mode 100644 index 00000000000..de261236d93 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_6.rs @@ -0,0 +1,2 @@ +struct Foo; +struct Bar; // { dg-error "expected .usize. got .i32." } diff --git a/gcc/testsuite/rust/compile/continue1.rs b/gcc/testsuite/rust/compile/continue1.rs new file mode 100644 index 00000000000..994312b52cc --- /dev/null +++ b/gcc/testsuite/rust/compile/continue1.rs @@ -0,0 +1,10 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + let _fib = { + continue; // { dg-error "cannot 'continue' outside of a loop" } + // { dg-error "failed to type resolve expression" "" { target *-*-* } .-1 } + 123 + }; +} diff --git a/gcc/testsuite/rust/compile/deadcode_err1.rs b/gcc/testsuite/rust/compile/deadcode_err1.rs new file mode 100644 index 00000000000..1dbe95731e1 --- /dev/null +++ b/gcc/testsuite/rust/compile/deadcode_err1.rs @@ -0,0 +1,11 @@ +fn foo() -> i32 { + return 1; + + let mut a = 1; // { dg-warning "unreachable statement" } + a = 1.1; // { dg-warning "unreachable statement" } + // { dg-error "expected .. got .." "" { target *-*-* } .-1 } +} + +fn main() { + foo(); +} diff --git a/gcc/testsuite/rust/compile/deadcode_err2.rs b/gcc/testsuite/rust/compile/deadcode_err2.rs new file mode 100644 index 00000000000..8c0eb4617a7 --- /dev/null +++ b/gcc/testsuite/rust/compile/deadcode_err2.rs @@ -0,0 +1,16 @@ +fn foo() -> i32 { + return 1; + return 1.5; // { dg-error "expected .i32. got .." } + // { dg-warning "unreachable statement" "" { target *-*-* } .-1 } +} + +fn bar() -> i32 { + return 1.5; // { dg-error "expected .i32. got .." } + return 1; + // { dg-warning "unreachable statement" "" { target *-*-* } .-1 } +} + +fn main() { + foo(); + bar(); +} diff --git a/gcc/testsuite/rust/compile/debug-diagnostics-default.rs b/gcc/testsuite/rust/compile/debug-diagnostics-default.rs new file mode 100644 index 00000000000..90b0e575b45 --- /dev/null +++ b/gcc/testsuite/rust/compile/debug-diagnostics-default.rs @@ -0,0 +1,5 @@ +// Make sure we don't see any 'note's: +// { dg-bogus {note: } "" { target *-*-* } 0 } + +fn main() { +} diff --git a/gcc/testsuite/rust/compile/debug-diagnostics-off.rs b/gcc/testsuite/rust/compile/debug-diagnostics-off.rs new file mode 100644 index 00000000000..77b82b35e62 --- /dev/null +++ b/gcc/testsuite/rust/compile/debug-diagnostics-off.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-fno-rust-debug" } + +// Make sure we don't see any 'note's: +// { dg-bogus {note: } "" { target *-*-* } 0 } + +fn main() { +} diff --git a/gcc/testsuite/rust/compile/debug-diagnostics-on.rs b/gcc/testsuite/rust/compile/debug-diagnostics-on.rs new file mode 100644 index 00000000000..847fd24d7bd --- /dev/null +++ b/gcc/testsuite/rust/compile/debug-diagnostics-on.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-frust-debug" } + +// Just scan for one of the Rust front end debug diagnostics: +// { dg-message {note: Attempting to parse file: .+/gcc/testsuite/rust/compile/debug-diagnostics-on\.rs} "" { target *-*-* } 0 } + +fn main() { +} diff --git a/gcc/testsuite/rust/compile/doc_isolated_cr_block_comment.rs b/gcc/testsuite/rust/compile/doc_isolated_cr_block_comment.rs new file mode 100644 index 00000000000..0ada77f69cf --- /dev/null +++ b/gcc/testsuite/rust/compile/doc_isolated_cr_block_comment.rs @@ -0,0 +1,3 @@ +// { dg-error "Isolated CR" "" { target *-*-* } .+1 } +/** doc cr comment */ +pub fn main () { } diff --git a/gcc/testsuite/rust/compile/doc_isolated_cr_inner_block_comment.rs b/gcc/testsuite/rust/compile/doc_isolated_cr_inner_block_comment.rs new file mode 100644 index 00000000000..7db35341bee --- /dev/null +++ b/gcc/testsuite/rust/compile/doc_isolated_cr_inner_block_comment.rs @@ -0,0 +1,5 @@ +pub fn main () +{ +// { dg-error "Isolated CR" "" { target *-*-* } .+1 } + /*! doc cr comment */ +} diff --git a/gcc/testsuite/rust/compile/doc_isolated_cr_inner_line_comment.rs b/gcc/testsuite/rust/compile/doc_isolated_cr_inner_line_comment.rs new file mode 100644 index 00000000000..d75da75e218 --- /dev/null +++ b/gcc/testsuite/rust/compile/doc_isolated_cr_inner_line_comment.rs @@ -0,0 +1,5 @@ +pub fn main () +{ +// { dg-error "Isolated CR" "" { target *-*-* } .+1 } + //! doc cr comment +} diff --git a/gcc/testsuite/rust/compile/doc_isolated_cr_line_comment.rs b/gcc/testsuite/rust/compile/doc_isolated_cr_line_comment.rs new file mode 100644 index 00000000000..7b6ef989c30 --- /dev/null +++ b/gcc/testsuite/rust/compile/doc_isolated_cr_line_comment.rs @@ -0,0 +1,3 @@ +// { dg-error "Isolated CR" "" { target *-*-* } .+1 } +/// doc cr comment +pub fn main () { } diff --git a/gcc/testsuite/rust/compile/dup_fields.rs b/gcc/testsuite/rust/compile/dup_fields.rs new file mode 100644 index 00000000000..ab39955eca0 --- /dev/null +++ b/gcc/testsuite/rust/compile/dup_fields.rs @@ -0,0 +1,23 @@ +struct S { a: i32, b: i32, c: u8, a: i128 } +// { dg-error "duplicate field" "" { target *-*-* } .-1 } + +union U + { + a: i32, + b: i32, + c: u8, + b: char // { dg-error "duplicate field" "" { target *-*-* } } + } + +fn main () +{ + struct SS { alpha: i32, beta: i32, gamma: u8, gamma: i128 } + // { dg-error "duplicate field" "" { target *-*-* } .-1 } + + union UU + { + alpha: i32, beta: i32, + gamma: u8, beta: char + // { dg-error "duplicate field" "" { target *-*-* } .-1 } + } +} diff --git a/gcc/testsuite/rust/compile/empty_comment_before_match.rs b/gcc/testsuite/rust/compile/empty_comment_before_match.rs new file mode 100644 index 00000000000..3d344d3e758 --- /dev/null +++ b/gcc/testsuite/rust/compile/empty_comment_before_match.rs @@ -0,0 +1,7 @@ +fn foo (x: i8) -> i32 { // { dg-warning "function is never used" } + // + match x { + 1 => { return 1; } + _ => { return 0; } + } +} diff --git a/gcc/testsuite/rust/compile/expected_type_args2.rs b/gcc/testsuite/rust/compile/expected_type_args2.rs new file mode 100644 index 00000000000..79454202aad --- /dev/null +++ b/gcc/testsuite/rust/compile/expected_type_args2.rs @@ -0,0 +1,6 @@ +struct Foo(A); + +fn main() { + let a: Foo = Foo::(123); + // { dg-error "generic item takes at least 1 type arguments but 0 were supplied" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/expected_type_args3.rs b/gcc/testsuite/rust/compile/expected_type_args3.rs new file mode 100644 index 00000000000..ba07239207a --- /dev/null +++ b/gcc/testsuite/rust/compile/expected_type_args3.rs @@ -0,0 +1,8 @@ +struct Foo(A); + +impl Foo { + // { dg-error "generic item takes at least 1 type arguments but 0 were supplied" "" { target *-*-* } .-1 } + fn test() -> i32 { + 123 + } +} diff --git a/gcc/testsuite/rust/compile/func1.rs b/gcc/testsuite/rust/compile/func1.rs new file mode 100644 index 00000000000..6758a3898e3 --- /dev/null +++ b/gcc/testsuite/rust/compile/func1.rs @@ -0,0 +1,9 @@ +fn test(x: i32) -> bool { + return x + 1; // { dg-error "expected .bool. got .i32." } +} + +fn main() { + let an_integer = 5; + + let call_test = test(1); +} diff --git a/gcc/testsuite/rust/compile/func2.rs b/gcc/testsuite/rust/compile/func2.rs new file mode 100644 index 00000000000..0b8d999fec1 --- /dev/null +++ b/gcc/testsuite/rust/compile/func2.rs @@ -0,0 +1,7 @@ +fn test(a: i32, b: i32) -> i32 { + a + b +} + +fn main() { + let a = test(1); // { dg-error "unexpected number of arguments 1 expected 2" } +} diff --git a/gcc/testsuite/rust/compile/func3.rs b/gcc/testsuite/rust/compile/func3.rs new file mode 100644 index 00000000000..2a329476118 --- /dev/null +++ b/gcc/testsuite/rust/compile/func3.rs @@ -0,0 +1,9 @@ +fn test(a: i32, b: i32) -> i32 { + a + b +} + +fn main() { + let a = test(1, true); + // { dg-error "expected .i32. got .bool." "" { target *-*-* } .-1 } + // { dg-error "Type Resolution failure on parameter" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/func4.rs b/gcc/testsuite/rust/compile/func4.rs new file mode 100644 index 00000000000..3b2d2b0d773 --- /dev/null +++ b/gcc/testsuite/rust/compile/func4.rs @@ -0,0 +1,6 @@ +fn func() -> i32 { // { dg-error "expected .i32. got ...." } +} + +fn main() { + func(); +} diff --git a/gcc/testsuite/rust/compile/func5.rs b/gcc/testsuite/rust/compile/func5.rs new file mode 100644 index 00000000000..05624f524e9 --- /dev/null +++ b/gcc/testsuite/rust/compile/func5.rs @@ -0,0 +1,7 @@ +fn func() -> i32 { + return; // { dg-error "expected .i32. got ...." } +} + +fn main() { + func(); +} diff --git a/gcc/testsuite/rust/compile/generic-default1.rs b/gcc/testsuite/rust/compile/generic-default1.rs new file mode 100644 index 00000000000..0a132bf5d6b --- /dev/null +++ b/gcc/testsuite/rust/compile/generic-default1.rs @@ -0,0 +1,7 @@ +struct Foo(A); +// { dg-error "failed to resolve TypePath: i321" "" { target *-*-* } .-1 } + +fn main() { + let a; + a = Foo(123); +} diff --git a/gcc/testsuite/rust/compile/generics1.rs b/gcc/testsuite/rust/compile/generics1.rs new file mode 100644 index 00000000000..de1bbf5dafb --- /dev/null +++ b/gcc/testsuite/rust/compile/generics1.rs @@ -0,0 +1,11 @@ +// { dg-error "expected .i32. got .i8." "" { target *-*-* } 0 } + +struct GenericStruct(T, usize); + +fn main() { + let a2: GenericStruct; + a2 = GenericStruct::<_>(1, 456); + + let b2: i32 = a2.0; + let c2: usize = a2.1; +} diff --git a/gcc/testsuite/rust/compile/generics10.rs b/gcc/testsuite/rust/compile/generics10.rs new file mode 100644 index 00000000000..a734fa8a197 --- /dev/null +++ b/gcc/testsuite/rust/compile/generics10.rs @@ -0,0 +1,12 @@ +struct Foo(A, B); + +impl Foo { // { dg-error "defaults for type parameters are not allowed here" } + fn new(a: X, b: f32) -> Self { + Self(a, b) + } +} + +fn main() { + let a; + a = Foo::new(123, 456f32); +} diff --git a/gcc/testsuite/rust/compile/generics11.rs b/gcc/testsuite/rust/compile/generics11.rs new file mode 100644 index 00000000000..4d3b9e1777c --- /dev/null +++ b/gcc/testsuite/rust/compile/generics11.rs @@ -0,0 +1,12 @@ +struct Foo(T, bool); + +impl Foo { + fn test() -> i32 { + 123 + } +} + +fn main() { + let a = Foo::test(); + // { dg-error "type annotations needed" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/generics12.rs b/gcc/testsuite/rust/compile/generics12.rs new file mode 100644 index 00000000000..f1ac8b0314b --- /dev/null +++ b/gcc/testsuite/rust/compile/generics12.rs @@ -0,0 +1,6 @@ +fn main() { + bar(); + // { dg-error "type annotations needed" "" { target *-*-* } .-1 } +} + +fn bar() {} diff --git a/gcc/testsuite/rust/compile/generics13.rs b/gcc/testsuite/rust/compile/generics13.rs new file mode 100644 index 00000000000..05c75c5f63d --- /dev/null +++ b/gcc/testsuite/rust/compile/generics13.rs @@ -0,0 +1 @@ +struct Foo; // { dg-error "invalid order for generic parameters: lifetimes should always come before types" } diff --git a/gcc/testsuite/rust/compile/generics2.rs b/gcc/testsuite/rust/compile/generics2.rs new file mode 100644 index 00000000000..5812b133038 --- /dev/null +++ b/gcc/testsuite/rust/compile/generics2.rs @@ -0,0 +1,11 @@ +// { dg-error "expected .i32. got .i8." "" { target *-*-* } 0 } + +struct GenericStruct(T, usize); + +fn main() { + let a2: GenericStruct; + a2 = GenericStruct(1, 456); + + let b2: i32 = a2.0; + let c2: usize = a2.1; +} diff --git a/gcc/testsuite/rust/compile/generics3.rs b/gcc/testsuite/rust/compile/generics3.rs new file mode 100644 index 00000000000..2d4210588fb --- /dev/null +++ b/gcc/testsuite/rust/compile/generics3.rs @@ -0,0 +1,10 @@ +// { dg-error "expected .i32. got .i8." "" { target *-*-* } 0 } +struct GenericStruct(T, usize); + +fn main() { + let a2; + a2 = GenericStruct::(1, 456); + + let b2: i32 = a2.0; + let c2: usize = a2.1; +} diff --git a/gcc/testsuite/rust/compile/generics4.rs b/gcc/testsuite/rust/compile/generics4.rs new file mode 100644 index 00000000000..8af13586a37 --- /dev/null +++ b/gcc/testsuite/rust/compile/generics4.rs @@ -0,0 +1,16 @@ +struct GenericStruct(T, usize); + +fn main() { + let a2; + a2 = GenericStruct::(1, 456); // { dg-error "generic item takes at most 1 type arguments but 2 were supplied" } + // { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 } + // { dg-error {Failed to resolve expression of function call} "" { target *-*-* } .-2 } + // { duplicate _dg-error {failed to type resolve expression} "" { target *-*-* } .-3 } + + let b2: i32 = a2.0; + // { dg-error {Expected Tuple or ADT got: T\?} "" { target *-*-* } .-1 } + // { dg-error {failed to type resolve expression} "" { target *-*-* } .-2 } + let c2: usize = a2.1; + // { dg-error {Expected Tuple or ADT got: T\?} "" { target *-*-* } .-1 } + // { dg-error {failed to type resolve expression} "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/generics5.rs b/gcc/testsuite/rust/compile/generics5.rs new file mode 100644 index 00000000000..6c847b5a29b --- /dev/null +++ b/gcc/testsuite/rust/compile/generics5.rs @@ -0,0 +1,10 @@ +struct GenericStruct(T, usize); + +fn main() { + let a2; + a2 = GenericStruct::(1, 456); + // { dg-error "failed to resolve TypePath: T" "" { target *-*-* } .-1 } + + let b2: i32 = a2.0; + let c2: usize = a2.1; +} diff --git a/gcc/testsuite/rust/compile/generics6.rs b/gcc/testsuite/rust/compile/generics6.rs new file mode 100644 index 00000000000..3b81e1bbee1 --- /dev/null +++ b/gcc/testsuite/rust/compile/generics6.rs @@ -0,0 +1,31 @@ +struct Foo { + a: A, +} + +impl Foo { + fn test() -> i32 { // { dg-error "possible candidate" "TODO" { xfail *-*-* } } + 123 + } + + fn bar(self) -> isize { + self.a + } +} + +impl Foo { + fn test() -> i32 { // { dg-error "possible candidate" "TODO" { xfail *-*-* } } + 123 + } + + fn bar(self) -> f32 { + self.a + } +} + +fn main() { + let a: i32 = Foo::test(); // { dg-error "multiple applicable items in scope for: test" } + // { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 } + // { dg-error {Failed to resolve expression of function call} "" { target *-*-* } .-2 } + // { duplicate _dg-error {failed to type resolve expression} "" { target *-*-* } .-3 } +} + diff --git a/gcc/testsuite/rust/compile/generics7.rs b/gcc/testsuite/rust/compile/generics7.rs new file mode 100644 index 00000000000..2a41632e693 --- /dev/null +++ b/gcc/testsuite/rust/compile/generics7.rs @@ -0,0 +1,26 @@ +struct Foo { + a: A, +} + +impl Foo { + fn bar(self) -> isize { // { dg-error "duplicate definitions with name bar" } + self.a + } +} + +impl Foo { + fn bar(self) -> char { // { dg-error "duplicate definitions with name bar" } + self.a + } +} + +impl Foo { + fn bar(self) -> T { + self.a + } +} + +fn main() { + let a = Foo { a: 123 }; + a.bar(); +} diff --git a/gcc/testsuite/rust/compile/generics8.rs b/gcc/testsuite/rust/compile/generics8.rs new file mode 100644 index 00000000000..ceefc5d2c6a --- /dev/null +++ b/gcc/testsuite/rust/compile/generics8.rs @@ -0,0 +1,15 @@ +struct Foo(A, B); + +impl Foo { + fn test(a: T) -> T { + a + } +} + +impl Foo { + fn test() -> f32 { // { dg-error "duplicate definitions with name test" } + 123f32 + } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/generics9.rs b/gcc/testsuite/rust/compile/generics9.rs new file mode 100644 index 00000000000..3766703431e --- /dev/null +++ b/gcc/testsuite/rust/compile/generics9.rs @@ -0,0 +1,10 @@ +struct Foo(A, B); +// { dg-error "failed to resolve TypePath: B" "" { target *-*-* } .-1 } + +fn main() { + let a: Foo; + a = Foo::(true, (false, true)); + + let b: (bool, bool); + b = a.1; +} diff --git a/gcc/testsuite/rust/compile/implicit_returns_err1.rs b/gcc/testsuite/rust/compile/implicit_returns_err1.rs new file mode 100644 index 00000000000..973ba80fb86 --- /dev/null +++ b/gcc/testsuite/rust/compile/implicit_returns_err1.rs @@ -0,0 +1,12 @@ +fn test(x: i32) -> i32 { + if x > 1 { // { dg-error "expected .... got .." } + 1 + } else { + 2 + } + 3 +} + +fn main() { + let a = test(1); +} diff --git a/gcc/testsuite/rust/compile/implicit_returns_err2.rs b/gcc/testsuite/rust/compile/implicit_returns_err2.rs new file mode 100644 index 00000000000..fb90748871f --- /dev/null +++ b/gcc/testsuite/rust/compile/implicit_returns_err2.rs @@ -0,0 +1,10 @@ +fn test(x: i32) -> i32 { + // { dg-error "expected .i32. got .bool." "" { target *-*-* } .-1 } + return 1; + // { dg-warning "unreachable expression" "" { target *-*-* } .+1 } + true +} + +fn main() { + let a = test(1); +} diff --git a/gcc/testsuite/rust/compile/implicit_returns_err3.rs b/gcc/testsuite/rust/compile/implicit_returns_err3.rs new file mode 100644 index 00000000000..37b1c62414c --- /dev/null +++ b/gcc/testsuite/rust/compile/implicit_returns_err3.rs @@ -0,0 +1,9 @@ +fn test(x: i32) -> i32 { // { dg-error "expected .i32. got ...." } + if x > 1 { + 1 + } +} + +fn main() { + let a = test(9); +} diff --git a/gcc/testsuite/rust/compile/implicit_returns_err4.rs b/gcc/testsuite/rust/compile/implicit_returns_err4.rs new file mode 100644 index 00000000000..59c6a020d4c --- /dev/null +++ b/gcc/testsuite/rust/compile/implicit_returns_err4.rs @@ -0,0 +1,10 @@ +fn test(x: bool) -> bool { + // { dg-error "expected .bool. got ...." "" { target *-*-*} .-1 } + return x; + // { dg-warning "unreachable expression" "" { target *-*-* } .+1 } + () +} + +fn main() { + let a = test(true); +} diff --git a/gcc/testsuite/rust/compile/infer-crate-name.rs b/gcc/testsuite/rust/compile/infer-crate-name.rs new file mode 100644 index 00000000000..b0c0086c04c --- /dev/null +++ b/gcc/testsuite/rust/compile/infer-crate-name.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-fdump-tree-gimple" } +pub fn does_nothing() {} +fn main() { + does_nothing() +} +// { dg-final { scan-tree-dump-times {infer_crate_name::does_nothing} 2 gimple } } +// { dg-final { scan-tree-dump-times {infer_crate_name::main} 1 gimple } } diff --git a/gcc/testsuite/rust/compile/inline_1.rs b/gcc/testsuite/rust/compile/inline_1.rs new file mode 100644 index 00000000000..4b0f991765a --- /dev/null +++ b/gcc/testsuite/rust/compile/inline_1.rs @@ -0,0 +1,16 @@ +// { dg-additional-options "-fdump-tree-gimple" } +#[inline] +fn test_a() {} + +// { dg-final { scan-tree-dump-times {always_inline} 1 gimple } } +#[inline(always)] +fn test_b() {} + +#[inline(never)] +fn test_c() {} + +fn main() { + test_a(); + test_b(); + test_c(); +} diff --git a/gcc/testsuite/rust/compile/inline_2.rs b/gcc/testsuite/rust/compile/inline_2.rs new file mode 100644 index 00000000000..3665fdac804 --- /dev/null +++ b/gcc/testsuite/rust/compile/inline_2.rs @@ -0,0 +1,6 @@ +// { dg-additional-options "-w" } +#[inline(A)] // { dg-error "unknown inline option" } +fn test_a() {} + +#[inline(A, B)] // { dg-error "invalid number of arguments" } +fn test_b() {} diff --git a/gcc/testsuite/rust/compile/issue-1005.rs b/gcc/testsuite/rust/compile/issue-1005.rs new file mode 100644 index 00000000000..46c85eea91e --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1005.rs @@ -0,0 +1,4 @@ +// { dg-additional-options "-w" } +impl *const T { + fn test(self) {} +} diff --git a/gcc/testsuite/rust/compile/issue-1019.rs b/gcc/testsuite/rust/compile/issue-1019.rs new file mode 100644 index 00000000000..aea86a821c7 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1019.rs @@ -0,0 +1,19 @@ +trait A { + type Output; + + fn test(self, a: &T) -> &Self::Output; +} + +struct Foo { + // { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + start: T, + end: T, +} + +impl A for Foo { + type Output = X; + + fn test(self, a: &X) -> &Self::Output { + a + } +} diff --git a/gcc/testsuite/rust/compile/issue-1023.rs b/gcc/testsuite/rust/compile/issue-1023.rs new file mode 100644 index 00000000000..5a0fe6cf530 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1023.rs @@ -0,0 +1,4 @@ +// { dg-additional-options "-w" } +fn foo(e: &str) -> &str { + &"" +} diff --git a/gcc/testsuite/rust/compile/issue-1031.rs b/gcc/testsuite/rust/compile/issue-1031.rs new file mode 100644 index 00000000000..939f0f981e0 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1031.rs @@ -0,0 +1,17 @@ +extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + pub fn offset(dst: *const T, offset: isize) -> *const T; +} + +#[lang = "const_ptr"] +impl *const T { + pub const unsafe fn offset(self, count: isize) -> *const T { + // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } + unsafe { offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } + unsafe { self.offset(count as isize) } + } +} diff --git a/gcc/testsuite/rust/compile/issue-1034.rs b/gcc/testsuite/rust/compile/issue-1034.rs new file mode 100644 index 00000000000..23d77005452 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1034.rs @@ -0,0 +1,16 @@ +trait Foo { + type Output; + + fn test(self, slice: &T) -> &Self::Output; +} + +struct Bar(T); +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl Foo<[T]> for Bar { + type Output = [T]; + + fn test(self, slice: &[T]) -> &[T] { + slice + } +} diff --git a/gcc/testsuite/rust/compile/issue-1089.rs b/gcc/testsuite/rust/compile/issue-1089.rs new file mode 100644 index 00000000000..635af293dbb --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1089.rs @@ -0,0 +1,6 @@ +// { dg-additional-options "-w" } +pub mod test_mod; + +fn main() { + let a = test_mod::Test(123); +} diff --git a/gcc/testsuite/rust/compile/issue-1128.rs b/gcc/testsuite/rust/compile/issue-1128.rs new file mode 100644 index 00000000000..462426b679d --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1128.rs @@ -0,0 +1,6 @@ +pub trait Hasher { + fn write(&mut self, bytes: &[u8]); + fn write_u8(&mut self, i: u8) { + self.write(&[i]) + } +} diff --git a/gcc/testsuite/rust/compile/issue-1129-1.rs b/gcc/testsuite/rust/compile/issue-1129-1.rs new file mode 100644 index 00000000000..a15903983f0 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1129-1.rs @@ -0,0 +1,4 @@ +// { dg-additional-options "-w" } +fn write_u8(i: u8) { + let x: &[u8] = &[i]; +} diff --git a/gcc/testsuite/rust/compile/issue-1129-2.rs b/gcc/testsuite/rust/compile/issue-1129-2.rs new file mode 100644 index 00000000000..25d30faf4aa --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1129-2.rs @@ -0,0 +1,22 @@ +// { dg-additional-options "-w" } +pub trait Hasher { + fn finish(&self) -> u64; + fn write(&mut self, bytes: &[u8]); + fn write_u8(&mut self, i: u8) { + self.write(&[i]) + } +} + +struct SipHasher; + +impl Hasher for SipHasher { + #[inline] + fn write(&mut self, msg: &[u8]) { + loop {} + } + + #[inline] + fn finish(&self) -> u64 { + 0 + } +} diff --git a/gcc/testsuite/rust/compile/issue-1130.rs b/gcc/testsuite/rust/compile/issue-1130.rs new file mode 100644 index 00000000000..92200c7cd5f --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1130.rs @@ -0,0 +1,47 @@ +// { dg-additional-options "-w" } +mod mem { + extern "rust-intrinsic" { + fn size_of() -> usize; + fn transmute(_: U) -> V; + } +} + +impl u16 { + fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + unsafe { mem::transmute(self) } + } +} + +pub trait Hasher { + fn finish(&self) -> u64; + + fn write(&mut self, bytes: &[u8]); + + fn write_u8(&mut self, i: u8) { + self.write(&[i]) + } + + fn write_i8(&mut self, i: i8) { + self.write_u8(i as u8) + } + + fn write_u16(&mut self, i: u16) { + self.write(&i.to_ne_bytes()) + } + + fn write_i16(&mut self, i: i16) { + self.write_u16(i as u16) + } +} + +pub struct SipHasher; + +impl Hasher for SipHasher { + #[inline] + fn write(&mut self, msg: &[u8]) {} + + #[inline] + fn finish(&self) -> u64 { + 0 + } +} diff --git a/gcc/testsuite/rust/compile/issue-1131.rs b/gcc/testsuite/rust/compile/issue-1131.rs new file mode 100644 index 00000000000..fd158abc700 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1131.rs @@ -0,0 +1,4 @@ +extern "rust-intrinsic" { + fn size_of() -> usize; + fn offset(dst: *const T, offset: isize) -> *const T; +} diff --git a/gcc/testsuite/rust/compile/issue-1152.rs b/gcc/testsuite/rust/compile/issue-1152.rs new file mode 100644 index 00000000000..18eee9e6b4a --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1152.rs @@ -0,0 +1,8 @@ +fn test() { + let f = [0; -4_isize]; + // { dg-error "expected .usize. got .isize." "" { target *-*-* } .-1 } + // { dg-error "failed to type resolve expression" "" { target *-*-* } .-2 } + let f = [0_usize; -1_isize]; + // { dg-error "expected .usize. got .isize." "" { target *-*-* } .-1 } + // { dg-error "failed to type resolve expression" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/issue-1165.rs b/gcc/testsuite/rust/compile/issue-1165.rs new file mode 100644 index 00000000000..f5889698d70 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1165.rs @@ -0,0 +1,5 @@ +struct Foo(T); + +fn main() { + &Foo(123); +} diff --git a/gcc/testsuite/rust/compile/issue-1173.rs b/gcc/testsuite/rust/compile/issue-1173.rs new file mode 100644 index 00000000000..5c2a9173241 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1173.rs @@ -0,0 +1,23 @@ +// { dg-additional-options "-w" } + +#![feature(intrinsics)] + +mod mem { + extern "rust-intrinsic" { + pub fn transmute(_: U) -> V; + } +} + +pub trait Hasher { + fn write(&mut self, bytes: &[u8]); + fn write_u16(&mut self, i: u16) { + self.write(unsafe { &mem::transmute::<_, [u8; 2]>(i) }) + } +} + +pub struct SipHasher; + +impl Hasher for SipHasher { + #[inline] + fn write(&mut self, msg: &[u8]) {} +} diff --git a/gcc/testsuite/rust/compile/issue-1226.rs b/gcc/testsuite/rust/compile/issue-1226.rs new file mode 100644 index 00000000000..f5f9e5ff08d --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1226.rs @@ -0,0 +1,6 @@ +// { dg-additional-options "-w" } +const TEST: *mut u8 = 123 as *mut u8; + +fn test() { + let a = TEST; +} diff --git a/gcc/testsuite/rust/compile/issue-1234.rs b/gcc/testsuite/rust/compile/issue-1234.rs new file mode 100644 index 00000000000..c6d5932c004 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1234.rs @@ -0,0 +1,4 @@ +fn foo() -> u8 { + // { dg-warning "function is never used" "" { target *-*-* } .-1 } + 1u8 << 2u32 +} diff --git a/gcc/testsuite/rust/compile/issue-1235.rs b/gcc/testsuite/rust/compile/issue-1235.rs new file mode 100644 index 00000000000..098b337455f --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1235.rs @@ -0,0 +1,21 @@ +// { dg-additional-options "-w" } +struct FatPtr { + data: *const T, + len: usize, +} + +pub union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +impl [T] { + pub const fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub const fn len(&self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } +} diff --git a/gcc/testsuite/rust/compile/issue-1237.rs b/gcc/testsuite/rust/compile/issue-1237.rs new file mode 100644 index 00000000000..542be897949 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1237.rs @@ -0,0 +1,23 @@ +// { dg-additional-options "-w" } +mod intrinsics { + extern "rust-intrinsic" { + pub fn offset(ptr: *const T, count: isize) -> *const T; + } +} + +impl *const T { + pub unsafe fn offset(self, count: isize) -> *const T { + unsafe { intrinsics::offset(self, count) } + } +} + +impl [T] { + pub unsafe fn get_unchecked(&self, index: usize) -> &T { + unsafe { &*(self as *const [T] as *const T).offset(index as isize) } + } +} + +#[inline] +unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { + (unsafe { *buf.get_unchecked(start) } as u64) +} diff --git a/gcc/testsuite/rust/compile/issue-1251.rs b/gcc/testsuite/rust/compile/issue-1251.rs new file mode 100644 index 00000000000..b16e1e0b0d9 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1251.rs @@ -0,0 +1,14 @@ +// { dg-additional-options "-w" } +mod a { + pub mod b { + pub mod a { + pub fn foo() {} + } + } + + pub fn bidule() { + crate::a::b::a::foo() + } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/issue-1271.rs b/gcc/testsuite/rust/compile/issue-1271.rs new file mode 100644 index 00000000000..5dd6418de4c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1271.rs @@ -0,0 +1,5 @@ +// { dg-additional-options "-w" } +fn test() { + let a: &str = "TEST 1"; + let b: &str = &"TEST 2"; +} diff --git a/gcc/testsuite/rust/compile/issue-1289.rs b/gcc/testsuite/rust/compile/issue-1289.rs new file mode 100644 index 00000000000..343aaab078b --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1289.rs @@ -0,0 +1,43 @@ +extern "C" { + fn printf(s: *const i8, ...); +} + +mod intrinsics { + extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + pub fn offset(dst: *const T, offset: isize) -> *const T; + } +} + +#[lang = "mut_ptr"] +impl *mut T { + pub const unsafe fn offset(self, count: isize) -> *mut T { + unsafe { intrinsics::offset(self, count) as *mut T } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } +} + +#[lang = "const_ptr"] +impl *const T { + pub const unsafe fn offset(self, count: isize) -> *mut T { + // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } + unsafe { intrinsics::offset(self, count) as *mut T } + } + + pub const unsafe fn add(self, count: usize) -> Self { + // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } + unsafe { self.offset(count as isize) } + } +} + +fn main() -> i32 { + let a: *mut _ = &mut 123; + unsafe { + let _b = a.add(123); + } + + 0 +} diff --git a/gcc/testsuite/rust/compile/issue-1323-1.rs b/gcc/testsuite/rust/compile/issue-1323-1.rs new file mode 100644 index 00000000000..a6174253a21 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1323-1.rs @@ -0,0 +1,18 @@ +fn main() { + let mut x = [1, 2, 3]; + let y: i32 = x[0]; + print_int(y); +} + +extern "C" { + fn printf(s: *const i8, ...); +} + +fn print_int(value: i32) { + let s = "%d\n\0"; + let s_p = s as *const str; + let c_p = s_p as *const i8; + unsafe { + printf(c_p, value as isize); + } +} diff --git a/gcc/testsuite/rust/compile/issue-1323-2.rs b/gcc/testsuite/rust/compile/issue-1323-2.rs new file mode 100644 index 00000000000..45168b22fa7 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1323-2.rs @@ -0,0 +1,16 @@ +fn print_int(value: i32) { + let s = "%d\n\0"; + let s_p = s as *const str; + let c_p = s_p as *const i8; + unsafe { + printf(c_p, value as isize); + } +} + +fn main() { + print_int(5); +} + +extern "C" { + fn printf(s: *const i8, ...); +} diff --git a/gcc/testsuite/rust/compile/issue-1383.rs b/gcc/testsuite/rust/compile/issue-1383.rs new file mode 100644 index 00000000000..cca12e8fc71 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1383.rs @@ -0,0 +1,8 @@ +pub fn generic_function(a: X) -> X { + a +} + +fn main() -> i32 { + let a = generic_function(123); + a - 123 +} diff --git a/gcc/testsuite/rust/compile/issue-1393.rs b/gcc/testsuite/rust/compile/issue-1393.rs new file mode 100644 index 00000000000..e09f01b62e5 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1393.rs @@ -0,0 +1,13 @@ +fn tst() { + let a = 123; + let b = 0; + let _c = if b == 0 { + (a & 0x7fffff) << 1 + } else { + (a & 0x7fffff) | 0x800000 + }; +} + +fn main() { + tst() +} diff --git a/gcc/testsuite/rust/compile/issue-1447.rs b/gcc/testsuite/rust/compile/issue-1447.rs new file mode 100644 index 00000000000..e0543e6247c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1447.rs @@ -0,0 +1,28 @@ +// { dg-options "-w" } +struct PhantomData; + +struct Hasher { + _marker: PhantomData, +} + +struct Sip24Rounds; + +struct SipHasher24 { + hasher: Hasher, +} + +impl SipHasher24 { + pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 { + SipHasher24 { + hasher: Hasher::new_with_keys(), + } + } +} + +impl Hasher { + fn new_with_keys() -> Hasher { + Hasher { + _marker: PhantomData, + } + } +} diff --git a/gcc/testsuite/rust/compile/issue-407-2.rs b/gcc/testsuite/rust/compile/issue-407-2.rs new file mode 100644 index 00000000000..cb8027b9c7f --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-407-2.rs @@ -0,0 +1,21 @@ +// #407 +pub fn loopy() { + let mut a = 1; + // { dg-error {failed to parse expr with block in parsing expr statement} "" { target *-*-* } .+2 } + // { dg-error {failed to parse statement or expression without block in block expression} "" { target *-*-* } .+1 } + loop { + // { dg-error {failed to parse expr with block in parsing expr statement} "" { target *-*-* } .+2 } + // { dg-error {failed to parse statement or expression without block in block expression} "" { target *-*-* } .+1 } + if a < 40 { + a + = 1; // { dg-error "found unexpected token '=' in null denotation" } + // { dg-error {failed to parse expression for expression without block \(pratt-parsed expression is null\)} "" { target *-*-* } .-1 } + // { dg-error {failed to parse statement or expression without block in block expression} "" { target *-*-* } .-2 } + // { dg-error {failed to parse if body block expression in if expression} "" { target *-*-* } .-3 } + // { dg-error {could not parse loop body in \(infinite\) loop expression} "" { target *-*-* } .+1 } + } else { + break; + } + } +} +// { dg-error {unrecognised token '\}' for start of item} "" { target *-*-* } .-1 } +// { dg-error {failed to parse item in crate} "" { target *-*-* } .-2 } diff --git a/gcc/testsuite/rust/compile/issue-407.rs b/gcc/testsuite/rust/compile/issue-407.rs new file mode 100644 index 00000000000..530b7ddfc12 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-407.rs @@ -0,0 +1,9 @@ +// This already worked before the #409 code changes. +fn test() { + let mut a = 1; + a + = 1; // { dg-error "found unexpected token '=' in null denotation" } + // { dg-error {failed to parse expression for expression without block \(pratt-parsed expression is null\)} "" { target *-*-* } .-1 } + // { dg-error {failed to parse statement or expression without block in block expression} "" { target *-*-* } .-2 } + // { dg-error {unrecognised token 'integer literal' for start of item} "" { target *-*-* } .-3 } + // { dg-error {failed to parse item in crate} "" { target *-*-* } .-4 } +} diff --git a/gcc/testsuite/rust/compile/issue-557.rs b/gcc/testsuite/rust/compile/issue-557.rs new file mode 100644 index 00000000000..aeb5ba6755b --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-557.rs @@ -0,0 +1,4 @@ +// { dg-additional-options "-w" } +fn test(a: i32, _: i32) { + let _ = 42 + a; +} diff --git a/gcc/testsuite/rust/compile/issue-635-1.rs b/gcc/testsuite/rust/compile/issue-635-1.rs new file mode 100644 index 00000000000..dc6a4c2eece --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-635-1.rs @@ -0,0 +1,5 @@ +// { dg-additional-options "-w" } +fn test() -> i32 { + return 10000000000000000000000000000000000000000000; + // { dg-error "integer overflows the respective type .i32." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-635-2.rs b/gcc/testsuite/rust/compile/issue-635-2.rs new file mode 100644 index 00000000000..335218aa52c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-635-2.rs @@ -0,0 +1,5 @@ +// { dg-additional-options "-w" } +fn test() -> f32 { + return 10000000000000000000000000000000000000000000.0f32; + // { dg-error "decimal overflows the respective type .f32." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/lookup_err1.rs b/gcc/testsuite/rust/compile/lookup_err1.rs new file mode 100644 index 00000000000..4a96f9ff140 --- /dev/null +++ b/gcc/testsuite/rust/compile/lookup_err1.rs @@ -0,0 +1,7 @@ +fn test() { + fn nested() {} +} + +fn main() { + nested(); // { dg-error "Cannot find path .nested. in this scope" } +} diff --git a/gcc/testsuite/rust/compile/macro-issue1053-2.rs b/gcc/testsuite/rust/compile/macro-issue1053-2.rs new file mode 100644 index 00000000000..31459907c08 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro-issue1053-2.rs @@ -0,0 +1,5 @@ +macro_rules! m { + ($e:expr $(forbidden)*) => {{}}; // { dg-error "token .identifier. is not allowed after .expr. fragment" } + // { dg-error "required first macro rule in macro rules definition could not be parsed" "" { target *-*-* } .-1 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/macro-issue1053.rs b/gcc/testsuite/rust/compile/macro-issue1053.rs new file mode 100644 index 00000000000..1e968496e0c --- /dev/null +++ b/gcc/testsuite/rust/compile/macro-issue1053.rs @@ -0,0 +1,3 @@ +macro_rules! m { + ($e:expr $(,)*) => {{}}; +} diff --git a/gcc/testsuite/rust/compile/macro-issue1224.rs b/gcc/testsuite/rust/compile/macro-issue1224.rs new file mode 100644 index 00000000000..003bbcd5067 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro-issue1224.rs @@ -0,0 +1,9 @@ +macro_rules! impl_uint { + ($($ty:ident),*) => { + impl $ty {} // { dg-error "metavariable is still repeating at this depth" } + // { dg-error "unrecognised token" "" { target *-*-* } .-1 } // Spurious + // { dg-error "could not parse type" "" { target *-*-* } .-2 } // Spurious + }; +} + +impl_uint!(u8, u16, u32, u64, u128); diff --git a/gcc/testsuite/rust/compile/macro-issue1233.rs b/gcc/testsuite/rust/compile/macro-issue1233.rs new file mode 100644 index 00000000000..7fab787b9e8 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro-issue1233.rs @@ -0,0 +1,22 @@ +// { dg-additional-options "-frust-cfg=A -w" } + +macro_rules! impl_uint { + ($($ty:ident = $lang:literal),*) => { + $( + impl $ty { + pub fn to_le(self) -> Self { + #[cfg(not(A))] + { + self + } + #[cfg(A)] + { + self + } + } + } + )* + } +} + +impl_uint!(u8 = "u8", u16 = "u16", u32 = "u32"); diff --git a/gcc/testsuite/rust/compile/macro-issue1395-2.rs b/gcc/testsuite/rust/compile/macro-issue1395-2.rs new file mode 100644 index 00000000000..1df6a3a0038 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro-issue1395-2.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-frust-edition=2018" } + +macro_rules! try { + // { dg-error "expecting .identifier. but .try. found" "" { target *-*-* } .-1 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-2 } + () => {}; +} diff --git a/gcc/testsuite/rust/compile/macro-issue1395.rs b/gcc/testsuite/rust/compile/macro-issue1395.rs new file mode 100644 index 00000000000..b0368c1610f --- /dev/null +++ b/gcc/testsuite/rust/compile/macro-issue1395.rs @@ -0,0 +1,5 @@ +// Default edition is 2015 - this is valid + +macro_rules! try { + () => {}; +} diff --git a/gcc/testsuite/rust/compile/macro-issue1400-2.rs b/gcc/testsuite/rust/compile/macro-issue1400-2.rs new file mode 100644 index 00000000000..ba7b61b0b16 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro-issue1400-2.rs @@ -0,0 +1,32 @@ +macro_rules! foo { + ( ( $( $Trait: ident ),+ ) for $($Ty: ident)* ) => { + $( + impl $Trait for $Ty { + // { dg-error "different amount of matches used in merged repetitions: expected 4, got 1" "" { target *-*-* } .-1 } + fn bar() -> i32 { + 14 + } + } + )+ + } +} + +trait Foo { + fn bar() -> i32; +} + +trait Bar { + fn bar() -> i32; +} + +trait Baz { + fn bar() -> i32; +} + +trait Qux { + fn bar() -> i32; +} + +struct S; + +foo! {(Foo, Bar, Baz, Qux) for S} diff --git a/gcc/testsuite/rust/compile/macro-issue1400.rs b/gcc/testsuite/rust/compile/macro-issue1400.rs new file mode 100644 index 00000000000..971bd778054 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro-issue1400.rs @@ -0,0 +1,33 @@ +// { dg-additional-options "-w" } + +macro_rules! foo { + ( ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + $( + impl $Trait for $Ty { + fn bar() -> i32 { + 14 + } + } + )+ + } +} + +trait Foo { + fn bar() -> i32; +} + +trait Bar { + fn bar() -> i32; +} + +trait Baz { + fn bar() -> i32; +} + +trait Qux { + fn bar() -> i32; +} + +struct S; + +foo! {(Foo, Bar, Baz, Qux) for S} diff --git a/gcc/testsuite/rust/compile/macro1.rs b/gcc/testsuite/rust/compile/macro1.rs new file mode 100644 index 00000000000..8cd941891d0 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro1.rs @@ -0,0 +1,3 @@ +macro_rules! empty_parens { + () => (); +} diff --git a/gcc/testsuite/rust/compile/macro10.rs b/gcc/testsuite/rust/compile/macro10.rs new file mode 100644 index 00000000000..3f1453e2eda --- /dev/null +++ b/gcc/testsuite/rust/compile/macro10.rs @@ -0,0 +1,11 @@ +// { dg-additional-options "-w" } +macro_rules! foo { + {} => { + 15 + }; +} + +fn main() { + let a = foo!(); + let b = foo![]; +} diff --git a/gcc/testsuite/rust/compile/macro11.rs b/gcc/testsuite/rust/compile/macro11.rs new file mode 100644 index 00000000000..97b89a12d84 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro11.rs @@ -0,0 +1,11 @@ +macro_rules! call_f { + ($($f:ident)*) => { $($f();)* } +} + +fn f() {} + +// This is valid and should parse items +fn main() { + call_f!(f f f f); +} + diff --git a/gcc/testsuite/rust/compile/macro12.rs b/gcc/testsuite/rust/compile/macro12.rs new file mode 100644 index 00000000000..b75fbad2c2f --- /dev/null +++ b/gcc/testsuite/rust/compile/macro12.rs @@ -0,0 +1,8 @@ +// { dg-additional-options "-w" } +macro_rules! define_vars { + ($($v:ident)*) => { $(let $v = 15;)* } +} + +fn main() { + define_vars!(a0 b f __some_identifier); +} diff --git a/gcc/testsuite/rust/compile/macro13.rs b/gcc/testsuite/rust/compile/macro13.rs new file mode 100644 index 00000000000..eb8dfbbf393 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro13.rs @@ -0,0 +1,12 @@ +// { dg-additional-options "-w" } +macro_rules! create_type { + ($s:ident) => { + struct $s; + }; +} + +fn main() { + create_type!(A); + + let a = A; +} diff --git a/gcc/testsuite/rust/compile/macro14.rs b/gcc/testsuite/rust/compile/macro14.rs new file mode 100644 index 00000000000..b18c56eefc8 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro14.rs @@ -0,0 +1,10 @@ +// { dg-additional-options "-w" } +macro_rules! define_vars { + ($($v:ident)*) => { $(let $v = 15;)* } +} + +fn main() -> i32 { + define_vars!(a0 b f __some_identifier); + + b +} diff --git a/gcc/testsuite/rust/compile/macro15.rs b/gcc/testsuite/rust/compile/macro15.rs new file mode 100644 index 00000000000..02c739e415e --- /dev/null +++ b/gcc/testsuite/rust/compile/macro15.rs @@ -0,0 +1,12 @@ +// { dg-additional-options "-w" } +macro_rules! create_type { + ($s:ident) => { + struct $s; + }; +} + +create_type!(SomeOuterType); + +fn main() { + let a = SomeOuterType; +} diff --git a/gcc/testsuite/rust/compile/macro16.rs b/gcc/testsuite/rust/compile/macro16.rs new file mode 100644 index 00000000000..e5e56ed3f03 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro16.rs @@ -0,0 +1,11 @@ +fn main() { + macro_rules! create_type { + ($s:ident) => { + struct $s(i32); + }; + } + + create_type!(Wrapper); + + let _ = Wrapper(15); +} diff --git a/gcc/testsuite/rust/compile/macro17.rs b/gcc/testsuite/rust/compile/macro17.rs new file mode 100644 index 00000000000..743216529b7 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro17.rs @@ -0,0 +1,10 @@ +macro_rules! rep { + ($a:literal) => { $a }; // { dg-error "reached recursion limit" } + ($a:literal $(, $e:literal)*) => { // { dg-error "reached recursion limit" } + $a + rep!(0 $(, $e)*) // { dg-error "Failed to match" } + } +} + +fn main() -> i32 { + rep!(1, 2) +} diff --git a/gcc/testsuite/rust/compile/macro18.rs b/gcc/testsuite/rust/compile/macro18.rs new file mode 100644 index 00000000000..5418725b619 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro18.rs @@ -0,0 +1,14 @@ +// { dg-additional-options "-w" } + +macro_rules! take_stmt { + ($s:stmt) => { + $s; + }; +} + +fn main() -> i32 { + take_stmt!(let complete = 15;); // { dg-error "Failed to match any rule within macro" } + take_stmt!(let lacking = 14); + + 0 +} diff --git a/gcc/testsuite/rust/compile/macro19.rs b/gcc/testsuite/rust/compile/macro19.rs new file mode 100644 index 00000000000..1bf9a2bfa9d --- /dev/null +++ b/gcc/testsuite/rust/compile/macro19.rs @@ -0,0 +1,19 @@ +// { dg-additional-options "-w" } + +macro_rules! call_without_semi { + () => { + f() + }; + (block) => {{ + f() + }}; +} + +fn f() {} + +fn main() -> i32 { + call_without_semi!(); + call_without_semi!(block); + + 0 +} diff --git a/gcc/testsuite/rust/compile/macro2.rs b/gcc/testsuite/rust/compile/macro2.rs new file mode 100644 index 00000000000..a437655ef70 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro2.rs @@ -0,0 +1,3 @@ +macro_rules! empty_brackets { + [] => []; +} diff --git a/gcc/testsuite/rust/compile/macro20.rs b/gcc/testsuite/rust/compile/macro20.rs new file mode 100644 index 00000000000..9f3cbca012c --- /dev/null +++ b/gcc/testsuite/rust/compile/macro20.rs @@ -0,0 +1,16 @@ +macro_rules! define_trait { + ($assoc:ident, $i:item) => { + type $assoc; + + $i + }; +} + +trait DefinedThroughMacros { + define_trait!( + Inner, + fn takes_inner(i: Self::Inner) -> Self::Inner { + i + } + ); +} diff --git a/gcc/testsuite/rust/compile/macro21.rs b/gcc/testsuite/rust/compile/macro21.rs new file mode 100644 index 00000000000..9a1d773ec4b --- /dev/null +++ b/gcc/testsuite/rust/compile/macro21.rs @@ -0,0 +1,9 @@ +macro_rules! c_fn { + {$name:ident ($($arg_name:ident $arg_ty:ty),*) -> $ret_ty:ty} => { + fn $name($($arg_name: $arg_ty)*) -> $ret_ty; + }; +} + +extern "C" { + c_fn! {puts (s *const i8) -> i64} +} diff --git a/gcc/testsuite/rust/compile/macro22.rs b/gcc/testsuite/rust/compile/macro22.rs new file mode 100644 index 00000000000..bdc4bada270 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro22.rs @@ -0,0 +1,10 @@ +macro_rules! print { + () => { + fn puts(s: *const i8); + fn printf(fmt: *const i8, ...); + }; +} + +extern "C" { + print! {} +} diff --git a/gcc/testsuite/rust/compile/macro23.rs b/gcc/testsuite/rust/compile/macro23.rs new file mode 100644 index 00000000000..afaca9bc96b --- /dev/null +++ b/gcc/testsuite/rust/compile/macro23.rs @@ -0,0 +1,25 @@ +macro_rules! maybe_impl { + ($left:ident, $right:ident, $l_fn:ident, $r_fn:ident) => { + fn $l_fn(value: T) -> Maybe { + Maybe::$left(value) + } + + fn $r_fn() -> Maybe { + Maybe::$right + } + }; +} + +enum Maybe { + Just(T), + Nothing, +} + +impl Maybe { + maybe_impl!(Just, Nothing, just, nothing); +} + +fn main() { + let _ = Maybe::just(14); + let _: Maybe = Maybe::nothing(); +} diff --git a/gcc/testsuite/rust/compile/macro25.rs b/gcc/testsuite/rust/compile/macro25.rs new file mode 100644 index 00000000000..d92534c0747 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro25.rs @@ -0,0 +1,9 @@ +macro_rules! valid { + ($($a:literal)* $i:ident) => {{}}; +} + +fn main() { + valid!(1 one_lit); + valid!(identifier_only); + valid!(1 2 two_lits); +} diff --git a/gcc/testsuite/rust/compile/macro26.rs b/gcc/testsuite/rust/compile/macro26.rs new file mode 100644 index 00000000000..f6588e75eb0 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro26.rs @@ -0,0 +1,10 @@ +macro_rules! repeat { + ( $( $i:literal ),* ; $( $j:literal ),* ) => (( $( ($i,$j) ),* )) + // { dg-error "different amount of matches used in merged repetitions" "" { target *-*-* } .-1 } +} + +fn main() -> i32 { + let _ = repeat!(1, 2, 3; 2, 3); + + 0 +} diff --git a/gcc/testsuite/rust/compile/macro27.rs b/gcc/testsuite/rust/compile/macro27.rs new file mode 100644 index 00000000000..ee7833be0a6 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro27.rs @@ -0,0 +1,8 @@ +macro_rules! m { + ($a:expr tok) => { + // { dg-error "token .identifier. is not allowed after .expr. fragment" "" { target *-*-* } .-1 } + // { dg-error "required first macro rule in macro rules definition could not be parsed" "" { target *-*-* } .-2 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-3 } + $a + }; +} diff --git a/gcc/testsuite/rust/compile/macro28.rs b/gcc/testsuite/rust/compile/macro28.rs new file mode 100644 index 00000000000..8002f284ecf --- /dev/null +++ b/gcc/testsuite/rust/compile/macro28.rs @@ -0,0 +1,8 @@ +macro_rules! m { + ($a:expr $(tok $es:expr)*) => { + // { dg-error "token .identifier. is not allowed after .expr. fragment" "" { target *-*-* } .-1 } + // { dg-error "required first macro rule in macro rules definition could not be parsed" "" { target *-*-* } .-2 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-3 } + $a + }; +} diff --git a/gcc/testsuite/rust/compile/macro29.rs b/gcc/testsuite/rust/compile/macro29.rs new file mode 100644 index 00000000000..39f5021b74f --- /dev/null +++ b/gcc/testsuite/rust/compile/macro29.rs @@ -0,0 +1,8 @@ +macro_rules! m { + ($($es:expr)* tok) => { + // { dg-error "token .identifier. is not allowed after .expr. fragment" "" { target *-*-* } .-1 } + // { dg-error "required first macro rule in macro rules definition could not be parsed" "" { target *-*-* } .-2 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-3 } + $a + }; +} diff --git a/gcc/testsuite/rust/compile/macro3.rs b/gcc/testsuite/rust/compile/macro3.rs new file mode 100644 index 00000000000..e5d3e93e07b --- /dev/null +++ b/gcc/testsuite/rust/compile/macro3.rs @@ -0,0 +1,3 @@ +macro_rules! empty_curlies { + {} => {}; +} diff --git a/gcc/testsuite/rust/compile/macro30.rs b/gcc/testsuite/rust/compile/macro30.rs new file mode 100644 index 00000000000..35064bc0ee5 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro30.rs @@ -0,0 +1,8 @@ +macro_rules! m { + ($e:expr $f:expr) => { + // { dg-error "fragment is not allowed after .expr. fragment" "" { target *-*-* } .-1 } + // { dg-error "required first macro rule in macro rules definition could not be parsed" "" { target *-*-* } .-2 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-3 } + $e + }; +} diff --git a/gcc/testsuite/rust/compile/macro31.rs b/gcc/testsuite/rust/compile/macro31.rs new file mode 100644 index 00000000000..6674a5fe554 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro31.rs @@ -0,0 +1,8 @@ +macro_rules! m { + ($($e:expr)* $($f:expr)*) => { + // { dg-error "fragment is not allowed after .expr. fragment" "" { target *-*-* } .-1 } + // { dg-error "required first macro rule in macro rules definition could not be parsed" "" { target *-*-* } .-2 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-3 } + $e + }; +} diff --git a/gcc/testsuite/rust/compile/macro32.rs b/gcc/testsuite/rust/compile/macro32.rs new file mode 100644 index 00000000000..d1d6305e6bd --- /dev/null +++ b/gcc/testsuite/rust/compile/macro32.rs @@ -0,0 +1,19 @@ +macro_rules! s { + ($s:stmt) => {{}}; +} + +macro_rules! multi_s { + ($($s:stmt)+) => {{}}; +} + +fn main() -> i32 { + s!(let a = 15); + s!(;); // Empty statement + s!(let a = 15;); // { dg-error "Failed to match any rule within macro" } + multi_s!(let a = 15;); + // ^ this actually gets parsed as two statements - one LetStmt and one + // empty statement. This is the same behavior as rustc, which you can + // see using a count!() macro + + 32 +} diff --git a/gcc/testsuite/rust/compile/macro33.rs b/gcc/testsuite/rust/compile/macro33.rs new file mode 100644 index 00000000000..2ccd33e50d3 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro33.rs @@ -0,0 +1,5 @@ +macro_rules! forbidden_frag { + ($t:ty $not_block:ident) => {{}}; // { dg-error "fragment specifier .ident. is not allowed after .ty. fragments" } + // { dg-error "required first macro rule in macro rules definition could not be parsed" "" { target *-*-* } .-1 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/macro34.rs b/gcc/testsuite/rust/compile/macro34.rs new file mode 100644 index 00000000000..105d042fd50 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro34.rs @@ -0,0 +1,3 @@ +macro_rules! allowed_after_expr_matcher { + (($t:expr) bok) => {{}}; // follow-set restrictions do not apply after a matcher, but they do apply inside the matcher +} diff --git a/gcc/testsuite/rust/compile/macro35.rs b/gcc/testsuite/rust/compile/macro35.rs new file mode 100644 index 00000000000..07b157b53c2 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro35.rs @@ -0,0 +1,7 @@ +macro_rules! inside_matcher { + (($e:expr tok) tok) => {{}}; // { dg-error "token .identifier. is not allowed after .expr. fragment" } + // { dg-error "failed to parse macro matcher" "" { target *-*-* } .-1 } + // { dg-error "failed to parse macro match" "" { target *-*-* } .-2 } + // { dg-error "required first macro rule" "" { target *-*-* } .-3 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-4 } +} diff --git a/gcc/testsuite/rust/compile/macro36.rs b/gcc/testsuite/rust/compile/macro36.rs new file mode 100644 index 00000000000..e5d66b22b7b --- /dev/null +++ b/gcc/testsuite/rust/compile/macro36.rs @@ -0,0 +1,3 @@ +macro_rules! ty_allowed { + ($t:ty $b:block) => {{}}; +} diff --git a/gcc/testsuite/rust/compile/macro37.rs b/gcc/testsuite/rust/compile/macro37.rs new file mode 100644 index 00000000000..5713d90130a --- /dev/null +++ b/gcc/testsuite/rust/compile/macro37.rs @@ -0,0 +1,5 @@ +macro_rules! invalid_after_zeroable { + ($e:expr $(,)* forbidden) => {{}}; // { dg-error "token .identifier. is not allowed after .expr. fragment" } + // { dg-error "required first macro rule" "" { target *-*-* } .-1 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/macro38.rs b/gcc/testsuite/rust/compile/macro38.rs new file mode 100644 index 00000000000..eb294aec83b --- /dev/null +++ b/gcc/testsuite/rust/compile/macro38.rs @@ -0,0 +1,5 @@ +macro_rules! invalid_after_zeroable_multi { + ($e:expr $(,)? $(;)* $(=>)? forbidden) => {{}}; // { dg-error "token .identifier. is not allowed after .expr. fragment" } + // { dg-error "required first macro rule" "" { target *-*-* } .-1 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/macro39.rs b/gcc/testsuite/rust/compile/macro39.rs new file mode 100644 index 00000000000..f5c498cc8ef --- /dev/null +++ b/gcc/testsuite/rust/compile/macro39.rs @@ -0,0 +1,5 @@ +macro_rules! m { + ($e:expr (, parenthesis_forbidden)) => {{}}; // { dg-error "token .\\(. at start of matcher is not allowed after .expr. fragment" } + // { dg-error "required first macro rule" "" { target *-*-* } .-1 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/macro4.rs b/gcc/testsuite/rust/compile/macro4.rs new file mode 100644 index 00000000000..47ff6c93d87 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro4.rs @@ -0,0 +1,3 @@ +macro_rules! one_keyword { + (kw) => {}; +} diff --git a/gcc/testsuite/rust/compile/macro40.rs b/gcc/testsuite/rust/compile/macro40.rs new file mode 100644 index 00000000000..7151f3a83bc --- /dev/null +++ b/gcc/testsuite/rust/compile/macro40.rs @@ -0,0 +1,48 @@ +// { dg-additional-options "-w" } + +macro_rules! t { + () => { + i32 + }; +} + +macro_rules! s { + () => { + *const i8 + }; +} + +extern "C" { + fn printf(s: s!(), ...); +} + +fn square(arg: t!()) -> t!() { + let input: t!() = arg; + + input * input +} + +trait Trait { + fn f() -> t!(); + fn g(arg: t!()); +} + +struct Wrapper { + inner: t!(), +} + +impl Trait for Wrapper { + fn f() -> t!() { + 1 + } + + fn g(arg: t!()) {} +} + +fn id(arg: T) -> T { + arg +} + +fn main() { + id::(15); +} diff --git a/gcc/testsuite/rust/compile/macro41.rs b/gcc/testsuite/rust/compile/macro41.rs new file mode 100644 index 00000000000..38244222924 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro41.rs @@ -0,0 +1,13 @@ +macro_rules! empty { + ($($t:tt)*) => {}; +} + +empty! {nothing} +empty! {struct OuterItem;} +empty! {} + +fn main() { + empty! {as statement}; + empty! {any child item}; + empty! {}; +} diff --git a/gcc/testsuite/rust/compile/macro42.rs b/gcc/testsuite/rust/compile/macro42.rs new file mode 100644 index 00000000000..52d150b82ba --- /dev/null +++ b/gcc/testsuite/rust/compile/macro42.rs @@ -0,0 +1,32 @@ +// { dg-additional-options "-w -frust-cfg=A" } +#[rustc_builtin_macro] +macro_rules! cfg { + () => {{}}; +} + +fn main() -> i32 { + let mut res = 0; + if cfg!(A) { + res = 1; + } + + if cfg!(A) { + res = 2; + } else { + res = 3; + } + + if cfg!(A) { + res = 4; + } else if cfg!(A) { + res = 5; + } + + let res = if cfg!(A) { + 6 + } else { + 7 + }; + + return res; +} diff --git a/gcc/testsuite/rust/compile/macro5.rs b/gcc/testsuite/rust/compile/macro5.rs new file mode 100644 index 00000000000..a5d80952e28 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro5.rs @@ -0,0 +1,3 @@ +macro_rules! rust_keyword { + (fn) => {}; +} diff --git a/gcc/testsuite/rust/compile/macro6.rs b/gcc/testsuite/rust/compile/macro6.rs new file mode 100644 index 00000000000..0ca35ba6888 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro6.rs @@ -0,0 +1,11 @@ +macro_rules! zero_or_one { + ($($a:literal)?) => { // { dg-error "invalid amount of matches for macro invocation. Expected between 0 and 1, got 2" } + f(); + } +} + +fn main() { + zero_or_one!(); + zero_or_one!(14); + zero_or_one!(125 12 "gcc"); // { dg-error "Failed to match any rule within macro" } +} diff --git a/gcc/testsuite/rust/compile/macro7.rs b/gcc/testsuite/rust/compile/macro7.rs new file mode 100644 index 00000000000..abc48057c54 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro7.rs @@ -0,0 +1,13 @@ +fn f() {} + +macro_rules! one_or_more { + ($($a:literal)+) => { // { dg-error "invalid amount of matches for macro invocation" } + f(); + }; +} + +fn main() { + one_or_more!(1 1 1 1 1 1 1 1 1 1 1 "rust" 'c'); + one_or_more!(1); + one_or_more!(); // { dg-error "Failed to match any rule within macro" } +} diff --git a/gcc/testsuite/rust/compile/macro8.rs b/gcc/testsuite/rust/compile/macro8.rs new file mode 100644 index 00000000000..d3e8af93a6e --- /dev/null +++ b/gcc/testsuite/rust/compile/macro8.rs @@ -0,0 +1,12 @@ +fn f() {} + +macro_rules! expr { + ($($a:expr)?) => { + f(); + }; +} + +fn main() { + expr!(); + expr!(14); +} diff --git a/gcc/testsuite/rust/compile/macro9.rs b/gcc/testsuite/rust/compile/macro9.rs new file mode 100644 index 00000000000..9a59089b1e4 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro9.rs @@ -0,0 +1,17 @@ +macro_rules! add { + ($e:expr, $($es:expr),*) => { + $e + add!($($es),*) + }; + ($e:expr) => { + $e + }; +} + +fn main() -> i32 { + let a = add!(15 2 9); // { dg-error "Failed to match any rule within macro" } + let b = add!(15); + let b = add!(15 14); // { dg-error "Failed to match any rule within macro" } + let b = add!(15, 14,); // { dg-error "Failed to match any rule within macro" } + + 0 +} diff --git a/gcc/testsuite/rust/compile/macro_return.rs b/gcc/testsuite/rust/compile/macro_return.rs new file mode 100644 index 00000000000..8b06f875cc0 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro_return.rs @@ -0,0 +1,10 @@ +// { dg-additional-options "-w" } + +macro_rules! add { + ($a:expr) => { $a }; + ($a:expr, $($b:expr),+) => { $a + add!($($b),*) } +} + +fn main() -> i32 { + add!(add!(1, 2)) +} diff --git a/gcc/testsuite/rust/compile/match1.rs b/gcc/testsuite/rust/compile/match1.rs new file mode 100644 index 00000000000..f649f3a1931 --- /dev/null +++ b/gcc/testsuite/rust/compile/match1.rs @@ -0,0 +1,16 @@ +enum Foo { + A, + B, + C(char), + D { x: i64, y: i64 }, +} + +fn inspect(f: Foo) { + match f { + Foo::A => {} + Foo::B => {} + Foo::C(a, b) => {} + // { dg-error "this pattern has 2 fields but the corresponding tuple variant has 1 field" "" { target *-*-* } .-1 } + Foo::D { x, y } => {} + } +} diff --git a/gcc/testsuite/rust/compile/match2.rs b/gcc/testsuite/rust/compile/match2.rs new file mode 100644 index 00000000000..359936a187c --- /dev/null +++ b/gcc/testsuite/rust/compile/match2.rs @@ -0,0 +1,15 @@ +enum Foo { + A, + B, + C(char), + D { x: i64, y: i64 }, +} + +fn inspect(f: Foo) { + match f { + Foo::A => {} + Foo::B => {} + Foo::C(x) => {} + Foo::D { y } => {} // { dg-error "pattern does not mention fields x" } + } +} diff --git a/gcc/testsuite/rust/compile/match3.rs b/gcc/testsuite/rust/compile/match3.rs new file mode 100644 index 00000000000..98181e85197 --- /dev/null +++ b/gcc/testsuite/rust/compile/match3.rs @@ -0,0 +1,16 @@ +enum Foo { + A, + B, + C(char), + D { x: i64, y: i64 }, +} + +fn inspect(f: Foo) { + match f { + Foo::A => {} + Foo::B => {} + Foo::C(x) => {} + Foo::D { z } => {} // { dg-error "variant D does not have a field named z" } + // { dg-error "pattern does not mention fields x, y" "" { target *-*-* } .-1 } + } +} diff --git a/gcc/testsuite/rust/compile/match4.rs b/gcc/testsuite/rust/compile/match4.rs new file mode 100644 index 00000000000..35b90a64fa5 --- /dev/null +++ b/gcc/testsuite/rust/compile/match4.rs @@ -0,0 +1,16 @@ +enum Foo { + A, + B, + C(char), + D { x: i64, y: i64 }, +} + +fn inspect(f: Foo) { + match f { + Foo::A => {} + Foo::B => {} + Foo::C { a } => {} + // { dg-error "expected struct variant, found tuple variant C" "" { target *-*-* } .-1 } + Foo::D { x, y } => {} + } +} diff --git a/gcc/testsuite/rust/compile/match5.rs b/gcc/testsuite/rust/compile/match5.rs new file mode 100644 index 00000000000..a5f934d6aeb --- /dev/null +++ b/gcc/testsuite/rust/compile/match5.rs @@ -0,0 +1,15 @@ +enum Foo { + A, + B, + C(char), + D { x: i64, y: i64 }, +} + +fn inspect(f: Foo) { + match f { + Foo::A => {} + Foo::B => {} + Foo::C(a) => {} + Foo::D(x, y) => {} // { dg-error "expected tuple struct or tuple variant, found struct variant 'Foo::D'" } + } +} diff --git a/gcc/testsuite/rust/compile/match6.rs b/gcc/testsuite/rust/compile/match6.rs new file mode 100644 index 00000000000..8fe06f7c116 --- /dev/null +++ b/gcc/testsuite/rust/compile/match6.rs @@ -0,0 +1,18 @@ +fn foo() -> bool { + true +} + +fn int32() -> i32 { + 1 +} + +fn bar() -> i32 { + match foo() { + true => int32(), + false => 0 + } +} + +fn main() -> () { + bar(); +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/match7.rs b/gcc/testsuite/rust/compile/match7.rs new file mode 100644 index 00000000000..b16a1883522 --- /dev/null +++ b/gcc/testsuite/rust/compile/match7.rs @@ -0,0 +1,12 @@ +fn bar (x: u8, y: u8) -> i32 { + match (x, y) { + (1, 1) => { return 1; } + (1, _) => { return -1; } + } + + return 0; +} + +fn main () -> () { + bar (1, 2); +} diff --git a/gcc/testsuite/rust/compile/method1.rs b/gcc/testsuite/rust/compile/method1.rs new file mode 100644 index 00000000000..18652406085 --- /dev/null +++ b/gcc/testsuite/rust/compile/method1.rs @@ -0,0 +1,13 @@ +struct Foo(i32); +impl Foo { + fn test() {} +} + +pub fn main() { + let a; + a = Foo(123); + + a.test(); + // { dg-error "failed to resolve method for .test." "" { target *-*-* } .-1 } + // { dg-error {failed to type resolve expression} "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/method2.rs b/gcc/testsuite/rust/compile/method2.rs new file mode 100644 index 00000000000..c8699f77c6a --- /dev/null +++ b/gcc/testsuite/rust/compile/method2.rs @@ -0,0 +1,16 @@ +struct Foo(A, B); + +impl Foo { + fn test(self, a: X) -> X { + a + } +} + +fn main() { + let a; + a = Foo(123, 456f32); + + let b; + b = a.test::(false); + // { dg-error "failed to resolve TypePath: asfasfr" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/mismatch-crate-name.rs b/gcc/testsuite/rust/compile/mismatch-crate-name.rs new file mode 100644 index 00000000000..e259b9e46cc --- /dev/null +++ b/gcc/testsuite/rust/compile/mismatch-crate-name.rs @@ -0,0 +1,4 @@ +// { dg-additional-options "-frust-crate=another_name" } +#![crate_name = "legit_name"] +// { dg-error ".-frust-crate-name. and .#.crate_name.. are required to match, but .another_name. does not match .legit_name." "" { target *-*-* } .-1 } +fn main() {} diff --git a/gcc/testsuite/rust/compile/missing_middle/both_path.rs b/gcc/testsuite/rust/compile/missing_middle/both_path.rs new file mode 100644 index 00000000000..5e5ad15457a --- /dev/null +++ b/gcc/testsuite/rust/compile/missing_middle/both_path.rs @@ -0,0 +1,3 @@ +pub fn f() -> u32 { + 5 +} diff --git a/gcc/testsuite/rust/compile/missing_middle/explicit.not.rs b/gcc/testsuite/rust/compile/missing_middle/explicit.not.rs new file mode 100644 index 00000000000..e28288b0f99 --- /dev/null +++ b/gcc/testsuite/rust/compile/missing_middle/explicit.not.rs @@ -0,0 +1 @@ +mod other; diff --git a/gcc/testsuite/rust/compile/missing_middle/inner_path.rs b/gcc/testsuite/rust/compile/missing_middle/inner_path.rs new file mode 100644 index 00000000000..daf4e3cc25a --- /dev/null +++ b/gcc/testsuite/rust/compile/missing_middle/inner_path.rs @@ -0,0 +1,3 @@ +pub fn f() -> u32 { + 4 +} diff --git a/gcc/testsuite/rust/compile/missing_middle/other.rs b/gcc/testsuite/rust/compile/missing_middle/other.rs new file mode 100644 index 00000000000..0c0884ec968 --- /dev/null +++ b/gcc/testsuite/rust/compile/missing_middle/other.rs @@ -0,0 +1,3 @@ +pub fn f() -> u32 { + 2 +} diff --git a/gcc/testsuite/rust/compile/missing_middle/outer_path.rs b/gcc/testsuite/rust/compile/missing_middle/outer_path.rs new file mode 100644 index 00000000000..fbe5074191b --- /dev/null +++ b/gcc/testsuite/rust/compile/missing_middle/outer_path.rs @@ -0,0 +1,3 @@ +pub fn f() -> u32 { + 3 +} diff --git a/gcc/testsuite/rust/compile/missing_middle/sub/mod.rs b/gcc/testsuite/rust/compile/missing_middle/sub/mod.rs new file mode 100644 index 00000000000..f099d61e04a --- /dev/null +++ b/gcc/testsuite/rust/compile/missing_middle/sub/mod.rs @@ -0,0 +1,3 @@ +pub fn f() -> u32 { + 1 +} diff --git a/gcc/testsuite/rust/compile/missing_return1.rs b/gcc/testsuite/rust/compile/missing_return1.rs new file mode 100644 index 00000000000..00bf393dbb9 --- /dev/null +++ b/gcc/testsuite/rust/compile/missing_return1.rs @@ -0,0 +1,6 @@ +// { dg-error "expected .* got .*" "" { target *-*-* } 0 } +fn test1() -> i32 {} + +fn main() { + let call1 = test1(); +} diff --git a/gcc/testsuite/rust/compile/mod_missing_middle.rs b/gcc/testsuite/rust/compile/mod_missing_middle.rs new file mode 100644 index 00000000000..79633407671 --- /dev/null +++ b/gcc/testsuite/rust/compile/mod_missing_middle.rs @@ -0,0 +1,29 @@ +// { dg-additional-options "-w" } + +mod missing_middle { + mod sub; + + #[path = "explicit.not.rs"] + mod explicit; +} + +#[path = "missing_middle"] +mod with_outer_path_attr { + #[path = "outer_path.rs"] + mod inner; +} + +mod with_inner_path_attr { + #![path = "missing_middle"] + + #[path = "inner_path.rs"] + mod inner; +} + +#[path = "missing_middle"] +mod with_both_path_attr { + #![path = "this_is_ignored"] + + #[path = "both_path.rs"] + mod inner; +} diff --git a/gcc/testsuite/rust/compile/never_type_err1.rs b/gcc/testsuite/rust/compile/never_type_err1.rs new file mode 100644 index 00000000000..52b1283fadf --- /dev/null +++ b/gcc/testsuite/rust/compile/never_type_err1.rs @@ -0,0 +1,14 @@ +fn test() { + let a; + + // FIXME: Unimplemented features + a = if true { // { dg-error "expected .T.. got .!." } + return; + } else { + return; + }; +} + +fn main() { + test(); +} diff --git a/gcc/testsuite/rust/compile/privacy1.rs b/gcc/testsuite/rust/compile/privacy1.rs new file mode 100644 index 00000000000..1cc83c04abe --- /dev/null +++ b/gcc/testsuite/rust/compile/privacy1.rs @@ -0,0 +1,11 @@ +mod orange { + mod green { + fn sain() {} + pub fn doux() {} + } + + fn brown() { + green::sain(); // { dg-error "definition is private in this context" } + green::doux(); + } +} diff --git a/gcc/testsuite/rust/compile/privacy2.rs b/gcc/testsuite/rust/compile/privacy2.rs new file mode 100644 index 00000000000..3c0744928b1 --- /dev/null +++ b/gcc/testsuite/rust/compile/privacy2.rs @@ -0,0 +1,13 @@ +// { dg-additional-options "-w" } + +mod orange { + fn tangerine() {} + + mod green { + mod blue { + fn berry() { + tangerine(); + } + } + } +} diff --git a/gcc/testsuite/rust/compile/privacy3.rs b/gcc/testsuite/rust/compile/privacy3.rs new file mode 100644 index 00000000000..d48acea4786 --- /dev/null +++ b/gcc/testsuite/rust/compile/privacy3.rs @@ -0,0 +1,28 @@ +mod orange { + mod green { + fn sain_void() {} + fn sain() -> bool { + false + } + pub fn doux() {} + } + + fn brown() { + if green::sain() { + // { dg-error "definition is private in this context" "" { target *-*-* } .-1 } + green::doux(); + } + + { + green::sain(); + // { dg-error "definition is private in this context" "" { target *-*-* } .-1 } + green::sain(); + // { dg-error "definition is private in this context" "" { target *-*-* } .-1 } + green::sain_void() + // { dg-error "definition is private in this context" "" { target *-*-* } .-1 } + } + + let a = green::sain(); + // { dg-error "definition is private in this context" "" { target *-*-* } .-1 } + } +} diff --git a/gcc/testsuite/rust/compile/privacy4.rs b/gcc/testsuite/rust/compile/privacy4.rs new file mode 100644 index 00000000000..d1ce0afd654 --- /dev/null +++ b/gcc/testsuite/rust/compile/privacy4.rs @@ -0,0 +1,19 @@ +mod orange { + mod green { + fn bean(value: T) -> T { + value + } + } + + fn brown() { + green::bean::(false); + // { dg-error "definition is private in this context" "" { target *-*-* } .-1 } + let a = green::bean::(15); + // { dg-error "definition is private in this context" "" { target *-*-* } .-1 } + + struct S; + + let s = green::bean(S); + // { dg-error "definition is private in this context" "" { target *-*-* } .-1 } + } +} diff --git a/gcc/testsuite/rust/compile/privacy5.rs b/gcc/testsuite/rust/compile/privacy5.rs new file mode 100644 index 00000000000..0e0e496dde2 --- /dev/null +++ b/gcc/testsuite/rust/compile/privacy5.rs @@ -0,0 +1,17 @@ +mod orange { + mod green { + struct Foo; + pub(in orange) struct Bar; + pub struct Baz; + } + + fn brown() { + let _ = green::Foo; // { dg-error "definition is private in this context" } + let _ = green::Bar; + let _ = green::Baz; + + let _: green::Foo; // { dg-error "definition is private in this context" } + + fn any(a0: green::Foo, a1: green::Bar) {} // { dg-error "20:definition is private in this context" } + } +} diff --git a/gcc/testsuite/rust/compile/privacy6.rs b/gcc/testsuite/rust/compile/privacy6.rs new file mode 100644 index 00000000000..487ed024209 --- /dev/null +++ b/gcc/testsuite/rust/compile/privacy6.rs @@ -0,0 +1,39 @@ +// { dg-additional-options "-w" } + +struct Adt; +enum EAdt { + V0, + V1, +} +struct Registers { + r0: i64, + r1: i64, + r2: i64, + r3: i64, +} +trait Foo {} + +fn foo1(value: bool) {} +fn foo2(value: char) {} +fn foo3(value: i32) {} +fn foo4(value: u16) {} +fn foo5(value: f64) {} +fn foo6(value: usize) {} +fn foo7(value: isize) {} +fn foo8(value: Adt) {} +fn foo9(value: EAdt) {} +fn foo10(value: &str) {} +fn foo11(value: *const i8) {} +fn foo12(value: T) {} +fn foo13(value: [i32; 5]) {} +fn foo14(value: [Adt]) {} +fn foo15(value: fn(i32) -> i32) {} +fn foo16(value: (i32, Adt)) {} +fn foo17(value: (i32, [f64; 5])) {} +fn foo18(value: Registers) {} +fn foo19(value: &dyn Foo) {} +fn foo20(value: &[Adt]) {} +// FIXME: Uncomment once #1257 is fixed +// fn foo21(value: fn(i32)) {} +// fn foo22(value: fn()) {} +fn foo23(value: fn() -> i32) {} diff --git a/gcc/testsuite/rust/compile/pub_restricted_1.rs b/gcc/testsuite/rust/compile/pub_restricted_1.rs new file mode 100644 index 00000000000..9bda9682403 --- /dev/null +++ b/gcc/testsuite/rust/compile/pub_restricted_1.rs @@ -0,0 +1,13 @@ +pub mod foo { + pub mod bar { + pub fn baz() {} + + pub(in foo::bar) struct A0; + } +} + +pub(in foo::fah::baz) struct A1; // { dg-error "cannot find simple path segment .fah." } +pub(in fro::bulator::saindoux) struct A2; // { dg-error "cannot find simple path segment .fro." } +pub(in foo::bar::saindoux) struct A3; // { dg-error "cannot find simple path segment .saindoux." } + +fn main() {} diff --git a/gcc/testsuite/rust/compile/pub_restricted_2.rs b/gcc/testsuite/rust/compile/pub_restricted_2.rs new file mode 100644 index 00000000000..8588f2775ca --- /dev/null +++ b/gcc/testsuite/rust/compile/pub_restricted_2.rs @@ -0,0 +1,18 @@ +// { dg-additional-options "-w" } + +mod foo { + mod bar { + mod baz { + pub(in baz) struct A0; + pub(in bar::baz) struct A1; + pub(in foo::bar::baz) struct A2; + + mod sain { + mod doux {} + } + + pub(in sain) struct A3; // { dg-error "restricted path is not an ancestor of the current module" } + pub(in sain::doux) struct A4; // { dg-error "restricted path is not an ancestor of the current module" } + } + } +} diff --git a/gcc/testsuite/rust/compile/pub_restricted_3.rs b/gcc/testsuite/rust/compile/pub_restricted_3.rs new file mode 100644 index 00000000000..d477385d761 --- /dev/null +++ b/gcc/testsuite/rust/compile/pub_restricted_3.rs @@ -0,0 +1,11 @@ +// { dg-additional-options "-w" } + +mod foo { + mod bar { + pub(in foo) fn baz() {} + } + + fn baz() { + bar::baz(); // no error, foo::bar::baz is public in foo + } +} diff --git a/gcc/testsuite/rust/compile/raw_identifiers_bad_keywords.rs b/gcc/testsuite/rust/compile/raw_identifiers_bad_keywords.rs new file mode 100644 index 00000000000..854d7e6edee --- /dev/null +++ b/gcc/testsuite/rust/compile/raw_identifiers_bad_keywords.rs @@ -0,0 +1,3 @@ +pub fn plus(n: i32, m: i32) -> i32 { + r#crate /* { dg-error "forbidden raw identifier" } */ +} diff --git a/gcc/testsuite/rust/compile/raw_identifiers_underscore.rs b/gcc/testsuite/rust/compile/raw_identifiers_underscore.rs new file mode 100644 index 00000000000..86e9013a50b --- /dev/null +++ b/gcc/testsuite/rust/compile/raw_identifiers_underscore.rs @@ -0,0 +1,3 @@ +pub fn s(num: i32) -> i32 { + r#_ * num /* { dg-error "not a valid raw identifier" } */ +} diff --git a/gcc/testsuite/rust/compile/rawbytestring.rs b/gcc/testsuite/rust/compile/rawbytestring.rs new file mode 100644 index 0000000000000000000000000000000000000000..9c6b762a7fd378206a3bfe21db5b708890f5466f GIT binary patch literal 3234 zcmbVOO>fgc5amjL#mG4T6)1rVl`5`1a^M^Zc^f;m2zI;c($Wfvf5=~A-pqd4PU65Z z<9Tmp-n`vS-O~56Y3cQwv*$CS<&wUX59E5=v|Go4UDeZ9>ni$0wkR&M$OnWLi=tR8 zvhYe0>#n0kp8Z~u3yqU0ZIOclm4066_dMaIdKBLE90VG(Y=lGOCeT&0tuLp+z$p*Er0}$>V{I!^8|YFtTxx z@X*l4>D0{rUt=35bE5|t9J_s{&GuboZD*@|GH+hjmxkvqUg|FRiNY&& zP6(%e4anlh3W@7JWKOd9E)p`E*!Jfr70=|kILq??taYC%vd4tW9O052FwtHy(W1l^5)-!Q6rkeY2pcOb5 zC5~Q^#`Cf!S&N9GM~?nelacMDHe;2ejYcV-D%(M~7r|5FJ&7hOIQ$Oo!_o8>9i>^x zV>X-Uc!7Jfq5+jI?0J=nn!sj`v1wMcU}PH?O>D8bJ*^GcSU|ak{Lxs!g8aAiFN}Pz A0RR91 literal 0 HcmV?d00001 diff --git a/gcc/testsuite/rust/compile/redef_error1.rs b/gcc/testsuite/rust/compile/redef_error1.rs --- /dev/null +++ b/gcc/testsuite/rust/compile/redef_error1.rs @@ -0,0 +1,8 @@ +struct S1 { + x: f64, + y: f64, +} + +struct S1(i32, bool); // { dg-error "redefined multiple times" } + +fn main() {} diff --git a/gcc/testsuite/rust/compile/redef_error2.rs b/gcc/testsuite/rust/compile/redef_error2.rs new file mode 100644 index 00000000000..65793bcda8a --- /dev/null +++ b/gcc/testsuite/rust/compile/redef_error2.rs @@ -0,0 +1,4 @@ +const TEST: i32 = 2; +const TEST: f32 = 3.0; // { dg-error "redefined multiple times" } + +fn main() {} diff --git a/gcc/testsuite/rust/compile/redef_error3.rs b/gcc/testsuite/rust/compile/redef_error3.rs new file mode 100644 index 00000000000..a4bf1ed3d8c --- /dev/null +++ b/gcc/testsuite/rust/compile/redef_error3.rs @@ -0,0 +1,9 @@ +fn test() -> bool { + true +} + +fn test() -> i32 { // { dg-error "redefined multiple times" } + 123 +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/redef_error4.rs b/gcc/testsuite/rust/compile/redef_error4.rs new file mode 100644 index 00000000000..a250c0ac00e --- /dev/null +++ b/gcc/testsuite/rust/compile/redef_error4.rs @@ -0,0 +1,27 @@ +struct Foo(i32, bool); + +impl Foo { + fn new(a: i32, b: bool) -> Foo { + Foo(a, b) + } + + fn test() -> i32 { + test() + } + + fn test() -> bool { // { dg-error "redefined multiple times" } + true + } +} + +fn test() -> i32 { + 123 +} + +fn main() { + let a; + a = Foo::new(1, true); + + let b; + b = Foo::test(); +} diff --git a/gcc/testsuite/rust/compile/redef_error5.rs b/gcc/testsuite/rust/compile/redef_error5.rs new file mode 100644 index 00000000000..dc6ad50e104 --- /dev/null +++ b/gcc/testsuite/rust/compile/redef_error5.rs @@ -0,0 +1,8 @@ +struct Foo(i32, bool); + +impl Foo { + const TEST: i32 = 123; + const TEST: bool = false; // { dg-error "redefined multiple times" } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/redef_error6.rs b/gcc/testsuite/rust/compile/redef_error6.rs new file mode 100644 index 00000000000..664c6ae9894 --- /dev/null +++ b/gcc/testsuite/rust/compile/redef_error6.rs @@ -0,0 +1,13 @@ +struct Foo(T, usize); + +impl Foo { + fn test() -> i32 { + 123 + } + + fn test(self) -> i32 { // { dg-error "redefined multiple times" } + self.0 + } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/reference1.rs b/gcc/testsuite/rust/compile/reference1.rs new file mode 100644 index 00000000000..ff791533754 --- /dev/null +++ b/gcc/testsuite/rust/compile/reference1.rs @@ -0,0 +1,6 @@ +fn main() { + let a = &123; + let b: &mut i32 = a; + // { dg-error "mismatched mutability" "" { target *-*-* } .-1 } + // { dg-error "expected .&mut i32. got .& i32." "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/self-path1.rs b/gcc/testsuite/rust/compile/self-path1.rs new file mode 100644 index 00000000000..425ba848fc0 --- /dev/null +++ b/gcc/testsuite/rust/compile/self-path1.rs @@ -0,0 +1,12 @@ +// { dg-additional-options "-w" } +struct foo; + +fn bar() -> self::foo { + crate::foo +} + +fn baz() { + let a: foo = self::bar(); + + crate::bar(); +} diff --git a/gcc/testsuite/rust/compile/self-path2.rs b/gcc/testsuite/rust/compile/self-path2.rs new file mode 100644 index 00000000000..b9b82cae5a6 --- /dev/null +++ b/gcc/testsuite/rust/compile/self-path2.rs @@ -0,0 +1,21 @@ +// { dg-additional-options "-w" } +struct foo; + +fn bar() -> self::foo { + crate::foo +} + +fn baz() { + let a: foo = self::bar(); + + crate::bar(); + + crate::self::foo(); + // { dg-error "failed to resolve: .self. in paths can only be used in start position" "" { target *-*-* } .-1 } +} + +type a = foo; +type b = crate::foo; +type c = self::foo; +type d = crate::self::foo; +// { dg-error "failed to resolve: .self. in paths can only be used in start position" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/shadow1.rs b/gcc/testsuite/rust/compile/shadow1.rs new file mode 100644 index 00000000000..77410e932da --- /dev/null +++ b/gcc/testsuite/rust/compile/shadow1.rs @@ -0,0 +1,7 @@ +fn main() { + let mut x = 5; + let mut x; + x = true; + x = x + 2; // { dg-error "cannot apply this operator to types bool and " } + // { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/specify-crate-name.rs b/gcc/testsuite/rust/compile/specify-crate-name.rs new file mode 100644 index 00000000000..a8679157024 --- /dev/null +++ b/gcc/testsuite/rust/compile/specify-crate-name.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-frust-crate=fancy_crate_name -fdump-tree-gimple" } +pub fn does_nothing() {} +fn main() { + does_nothing() +} +// { dg-final { scan-tree-dump-times {fancy_crate_name::does_nothing} 2 gimple } } +// { dg-final { scan-tree-dump-times {fancy_crate_name::main} 1 gimple } } diff --git a/gcc/testsuite/rust/compile/static_var1.rs b/gcc/testsuite/rust/compile/static_var1.rs new file mode 100644 index 00000000000..b3b5751c932 --- /dev/null +++ b/gcc/testsuite/rust/compile/static_var1.rs @@ -0,0 +1,5 @@ +static x = 3; // { dg-error "expecting ':' but '=' found" } + +fn main() {// { dg-error "failed to parse item in crate" } + let y = x +1; +} diff --git a/gcc/testsuite/rust/compile/stmt_with_block_err1.rs b/gcc/testsuite/rust/compile/stmt_with_block_err1.rs new file mode 100644 index 00000000000..8780d0feeac --- /dev/null +++ b/gcc/testsuite/rust/compile/stmt_with_block_err1.rs @@ -0,0 +1,17 @@ +fn test(x: i32) -> i32 { + if x > 1 { // { dg-error "expected .... got .." } + 1 + } else { + 2 + } + + { // { dg-error "expected .... got .." } + 3 + } + + 3 +} + +fn main() { + let a = test(0); +} diff --git a/gcc/testsuite/rust/compile/struct_align1.rs b/gcc/testsuite/rust/compile/struct_align1.rs new file mode 100644 index 00000000000..22eb6bc80fb --- /dev/null +++ b/gcc/testsuite/rust/compile/struct_align1.rs @@ -0,0 +1,19 @@ +#[repr(align(8))] +struct Foo { + x: i16, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + y: i8, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + z: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +#[repr(align(8))] +struct Bar(i8, i32); + +fn main () { + let f = Foo { x: 5, y: 2, z: 13 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = Bar (7, 262); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/struct_align2.rs b/gcc/testsuite/rust/compile/struct_align2.rs new file mode 100644 index 00000000000..ac490643a36 --- /dev/null +++ b/gcc/testsuite/rust/compile/struct_align2.rs @@ -0,0 +1,18 @@ + +fn main () { + + #[repr(align(8))] + struct Baz { + x: u16, + y: u32, + }; + + #[repr(align(4))] + struct Qux (u8, i16); + + let b = Baz { x: 5, y: 1984 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let c = Qux (1, 2); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/struct_init1.rs b/gcc/testsuite/rust/compile/struct_init1.rs new file mode 100644 index 00000000000..1875fb4f33e --- /dev/null +++ b/gcc/testsuite/rust/compile/struct_init1.rs @@ -0,0 +1,10 @@ +struct Foo { + a: f32, + b: f32, +} + +fn main() { + let a = Foo { 0: 10.0, 1: 20.0 }; // { dg-error "failed to resolve type for field" } + // { dg-error "unknown field" "" { target *-*-* } .-1 } + // { dg-prune-output "compilation terminated" } +} diff --git a/gcc/testsuite/rust/compile/struct_pack1.rs b/gcc/testsuite/rust/compile/struct_pack1.rs new file mode 100644 index 00000000000..eb9d879c1dc --- /dev/null +++ b/gcc/testsuite/rust/compile/struct_pack1.rs @@ -0,0 +1,19 @@ +#[repr(packed(2))] +struct Foo { + x: i16, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + y: i8, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + z: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +#[repr(packed)] +struct Bar(i8, i32); + +fn main () { + let f = Foo { x: 5, y: 2, z: 13 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = Bar (7, 262); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/struct_pack2.rs b/gcc/testsuite/rust/compile/struct_pack2.rs new file mode 100644 index 00000000000..e5f74c20bb0 --- /dev/null +++ b/gcc/testsuite/rust/compile/struct_pack2.rs @@ -0,0 +1,18 @@ + +fn main () { + + #[repr(packed(2))] + struct Baz { + x: u16, + y: u32, + }; + + #[repr(packed)] + struct Qux (u8, i16); + + let b = Baz { x: 5, y: 1984 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let c = Qux (1, 2); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/syntax-only.rs b/gcc/testsuite/rust/compile/syntax-only.rs new file mode 100644 index 00000000000..cd84907bf84 --- /dev/null +++ b/gcc/testsuite/rust/compile/syntax-only.rs @@ -0,0 +1,6 @@ +// { dg-additional-options "-fsyntax-only" } + +fn main() { + let mut a = 15; + a = true; +} diff --git a/gcc/testsuite/rust/compile/test_mod.rs b/gcc/testsuite/rust/compile/test_mod.rs new file mode 100644 index 00000000000..4b3c000236b --- /dev/null +++ b/gcc/testsuite/rust/compile/test_mod.rs @@ -0,0 +1,6 @@ +//! test_mod inner doc comment +//! +//! foo bar baz cake pizza carbs + +pub struct Test(pub i32); +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/torture/all_doc_comment_line_blocks.rs b/gcc/testsuite/rust/compile/torture/all_doc_comment_line_blocks.rs new file mode 100644 index 00000000000..b7368ba29ee --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/all_doc_comment_line_blocks.rs @@ -0,0 +1,45 @@ +// comment line not a doc +/* comment block not a doc */ + +//! inner line comment for most outer crate +/*! inner block comment for most outer crate */ + +// comment line not a doc +/* comment block not a doc */ + +/// outer doc line for module +/** outer doc block for module */ +pub mod module { + //! inner line doc + //!! inner line doc! + /*! inner block doc */ + /*!! inner block doc! */ + + // line comment + /// outer line doc + //// line comment + + /* block comment */ + /** outer block doc */ + /*** block comment */ + + mod block_doc_comments { + /* /* */ /** */ /*! */ */ + /*! /* */ /** */ /*! */ */ + /** /* */ /** */ /*! */ */ + mod item {} + } + + pub mod empty { + //! + /*!*/ + // + + /// + // the following warning is issued one line earlier + mod doc {} + /**/ + /***/ + } +} +pub fn main() {} diff --git a/gcc/testsuite/rust/compile/torture/all_doc_comment_line_blocks_crlf.rs b/gcc/testsuite/rust/compile/torture/all_doc_comment_line_blocks_crlf.rs new file mode 100644 index 00000000000..9f2f2207397 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/all_doc_comment_line_blocks_crlf.rs @@ -0,0 +1,48 @@ +// comment line not a doc +/* comment block not a doc */ + +//! inner line comment for most outer crate +/*! inner block comment for most outer crate */ + +// comment line not a doc +/* comment block not a doc */ + +/// outer doc line for module +/** outer doc block for module */ +pub mod module +{ + //! inner line doc + //!! inner line doc! + /*! inner block doc */ + /*!! inner block doc! */ + + // line comment + /// outer line doc + //// line comment + + /* block comment */ + /** outer block doc */ + /*** block comment */ + + mod block_doc_comments + { + /* /* */ /** */ /*! */ */ + /*! /* */ /** */ /*! */ */ + /** /* */ /** */ /*! */ */ + mod item { } + } + + pub mod empty + { + //! + /*!*/ + // + + /// + mod doc { } + + /**/ + /***/ + } +} +pub fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/arithmetic_expressions1.rs b/gcc/testsuite/rust/compile/torture/arithmetic_expressions1.rs new file mode 100644 index 00000000000..4c3ee77c835 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/arithmetic_expressions1.rs @@ -0,0 +1,30 @@ +// { dg-prune-output "warning: unused name" } as there are many of these expected. + +fn main() { + let a: i32 = 1; + let b: f32 = 5f32; + let c: bool = true; + + let a1: i32 = a + 1; + let a2: i32 = a - 2; + let a3: i32 = a * 3; + let a4: i32 = a / 4; + let a5: i32 = a % 5; + + let b1: f32 = b + 1f32; + let b2: f32 = b - 2f32; + let b3: f32 = b * 3f32; + let b4: f32 = b / 4f32; + // let b5: f32 = b % 5f32; + + let aa1: i32 = a & 1; + let aa2: i32 = a | 2; + let aa2: i32 = a ^ 3; + + let c1: bool = c & true; + let c2: bool = c | false; + let c3: bool = c ^ true; + + let aaa1: i32 = a << 1; + let aaa2: i32 = a >> 2; +} diff --git a/gcc/testsuite/rust/compile/torture/array_const_fold_1.rs b/gcc/testsuite/rust/compile/torture/array_const_fold_1.rs new file mode 100644 index 00000000000..e45c9389c93 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/array_const_fold_1.rs @@ -0,0 +1,2 @@ +const TEST: [i32; 16] = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8]; +// { dg-warning "unused name" "" { target *-*-* } .-1 } \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/array_const_fold_2.rs b/gcc/testsuite/rust/compile/torture/array_const_fold_2.rs new file mode 100644 index 00000000000..b42a68e5ddb --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/array_const_fold_2.rs @@ -0,0 +1,3 @@ +const SIZE: usize = 14 + 2; +const TEST: [i32; SIZE] = [2; SIZE]; +// { dg-warning "unused name" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/torture/array_function.rs b/gcc/testsuite/rust/compile/torture/array_function.rs new file mode 100644 index 00000000000..4e2b2e03f31 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/array_function.rs @@ -0,0 +1,8 @@ +fn foo() -> i32 { + 1 +} + + +fn main() { + let _a: [i32; 1] = [foo()]; +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/array_type_infer.rs b/gcc/testsuite/rust/compile/torture/array_type_infer.rs new file mode 100644 index 00000000000..6f21bf2420c --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/array_type_infer.rs @@ -0,0 +1,4 @@ +fn main() { + let arr: [_; 5] = [1, 2, 3, 4, 5]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/array_zero_length.rs b/gcc/testsuite/rust/compile/torture/array_zero_length.rs new file mode 100644 index 00000000000..3155b1c48c0 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/array_zero_length.rs @@ -0,0 +1,4 @@ +fn main() { + let arr = ["Hello"; 0]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/arrays1.rs b/gcc/testsuite/rust/compile/torture/arrays1.rs new file mode 100644 index 00000000000..7250e0fa2af --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/arrays1.rs @@ -0,0 +1,9 @@ +fn main() { + let xs: [i32; 5] = [1, 2, 3, 4, 5]; + let xy = [6, 7, 8]; + + let a = xs[0]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = xy[2]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/arrays2.rs b/gcc/testsuite/rust/compile/torture/arrays2.rs new file mode 100644 index 00000000000..55491f34524 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/arrays2.rs @@ -0,0 +1,8 @@ +fn main() { + let mut array: [i32; 3] = [0; 3]; + + let a = array[0]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let mut c; + c = array[2]; +} diff --git a/gcc/testsuite/rust/compile/torture/arrays3.rs b/gcc/testsuite/rust/compile/torture/arrays3.rs new file mode 100644 index 00000000000..372d969aa07 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/arrays3.rs @@ -0,0 +1,6 @@ +const TEST: usize = 6; + +fn main() { + let a: [_; 12] = [123; TEST * 2]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/arrays4.rs b/gcc/testsuite/rust/compile/torture/arrays4.rs new file mode 100644 index 00000000000..ac317fedf44 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/arrays4.rs @@ -0,0 +1,6 @@ +const TEST: usize = 4; + +fn main() { + let a: [_; TEST + 1 + 2] = [123; 7]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/arrays5.rs b/gcc/testsuite/rust/compile/torture/arrays5.rs new file mode 100644 index 00000000000..58950a17a15 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/arrays5.rs @@ -0,0 +1,6 @@ + +// Checks that we don't try to allocate a 4TB array during compilation +fn main () { + let x = [0; 4 * 1024 * 1024 * 1024 * 1024]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/arrays6.rs b/gcc/testsuite/rust/compile/torture/arrays6.rs new file mode 100644 index 00000000000..c7212d3f183 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/arrays6.rs @@ -0,0 +1,10 @@ + +// Checks that we don't try to allocate a 4TB array during compilation +fn foo() -> [u8; 4 * 1024 * 1024 * 1024 * 1024] { + [0; 4 * 1024 * 1024 * 1024 * 1024] +} + +fn main () { + let x = foo (); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/arrays_index1.rs b/gcc/testsuite/rust/compile/torture/arrays_index1.rs new file mode 100644 index 00000000000..1fe5de91bcf --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/arrays_index1.rs @@ -0,0 +1,9 @@ +fn main() { + let mut array: [i32; 3] = [0; 3]; + + let a = array[0]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let x = 0; + let mut c; + c = array[x+1]; +} diff --git a/gcc/testsuite/rust/compile/torture/arrays_index2.rs b/gcc/testsuite/rust/compile/torture/arrays_index2.rs new file mode 100644 index 00000000000..f9bee7748ee --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/arrays_index2.rs @@ -0,0 +1,4 @@ +fn main() { + let mut array: [i32; 3] = [0; 3]; + array[0] = 1; +} diff --git a/gcc/testsuite/rust/compile/torture/arrays_index3.rs b/gcc/testsuite/rust/compile/torture/arrays_index3.rs new file mode 100644 index 00000000000..8fa0a226d02 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/arrays_index3.rs @@ -0,0 +1,15 @@ +fn foo() -> usize { + 1 +} + +fn bar() -> [i32; 1] { + [0] +} + + + +fn main() -> () { + let a = [10]; + let _b = a[foo()]; + let _c = bar()[foo()]; +} diff --git a/gcc/testsuite/rust/compile/torture/as_bool_char.rs b/gcc/testsuite/rust/compile/torture/as_bool_char.rs new file mode 100644 index 00000000000..d687499384a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/as_bool_char.rs @@ -0,0 +1,36 @@ +extern "C" { fn abort (); } + +pub fn main () +{ + let t = true; + let f = false; + let one = t as u8; + let zero = f as u8; + + if one != 1 || zero != 0 { unsafe { abort (); } } + + let isizeone = true as isize; + let usizezero = false as usize; + + if isizeone != 1 || usizezero != 0 { unsafe { abort (); } } + + let i32zero = f as i32; + let u128one = t as u128; + + if u128one != 1 || i32zero != 0 { unsafe { abort (); } } + + let a = 'a'; + let b = 'b'; + let ua = a as u8; + let ib = b as i32; + + if (ua + 1) as i32 != ib { unsafe { abort (); } } + + let tt = ua; + let aa = tt as char; + + let ttt = tt + 1; + let ab = ttt as char; + + if aa != 'a' || ab != 'b' { unsafe { abort (); } } +} diff --git a/gcc/testsuite/rust/compile/torture/associated_types1.rs b/gcc/testsuite/rust/compile/torture/associated_types1.rs new file mode 100644 index 00000000000..bf181df7045 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/associated_types1.rs @@ -0,0 +1,12 @@ +pub trait Foo { + type A; + + fn boo(&self) -> ::A; +} + +fn foo2(x: I) { + // { dg-warning "function is never used: .foo2." "" { target *-*-* } .-1 } + x.boo(); +} + +pub fn main() {} diff --git a/gcc/testsuite/rust/compile/torture/autoderef1.rs b/gcc/testsuite/rust/compile/torture/autoderef1.rs new file mode 100644 index 00000000000..0cf070f1f37 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/autoderef1.rs @@ -0,0 +1,15 @@ +struct Foo(i32, bool); +struct Bar { + a: i32, + b: bool, +} + +fn main() { + let a = &Foo(123, false); + let _b: i32 = a.0; + let _c: bool = a.1; + + let a = &Bar { a: 456, b: false }; + let _b: i32 = a.a; + let _c: bool = a.b; +} diff --git a/gcc/testsuite/rust/compile/torture/block_expr1.rs b/gcc/testsuite/rust/compile/torture/block_expr1.rs new file mode 100644 index 00000000000..011cc1fc89d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/block_expr1.rs @@ -0,0 +1,29 @@ +fn test3(x: i32) -> i32 { + if x > 1 { + 5 + } else { + 0 + } +} + +fn test5(x: i32) -> i32 { + if x > 1 { + if x == 5 { + 7 + } else { + 9 + } + } else { + 0 + } +} + +fn main() { + let call3: i32 = { test3(3) + 2 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let call5 = { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let a = test5(5); + a + 1 + }; +} diff --git a/gcc/testsuite/rust/compile/torture/block_expr2.rs b/gcc/testsuite/rust/compile/torture/block_expr2.rs new file mode 100644 index 00000000000..7c3ff698097 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/block_expr2.rs @@ -0,0 +1,15 @@ +fn test() -> i32 { + 123 +} + +fn main() { + let a = { test() }; + let b = { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + if a > 10 { + a - 1 + } else { + a + 1 + } + }; +} diff --git a/gcc/testsuite/rust/compile/torture/block_expr3.rs b/gcc/testsuite/rust/compile/torture/block_expr3.rs new file mode 100644 index 00000000000..6914b6379d7 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/block_expr3.rs @@ -0,0 +1,14 @@ +fn main() { + let x = 111; + + let a = { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + if x == 10 { + 123 + } else if x < 10 { + 456 + } else { + 789 + } + }; +} diff --git a/gcc/testsuite/rust/compile/torture/block_expr4.rs b/gcc/testsuite/rust/compile/torture/block_expr4.rs new file mode 100644 index 00000000000..da033ef9ef4 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/block_expr4.rs @@ -0,0 +1,8 @@ +fn foo() -> isize { + 0 +} + +fn main() { + let a = foo(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/block_expr5.rs b/gcc/testsuite/rust/compile/torture/block_expr5.rs new file mode 100644 index 00000000000..7e164a949bb --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/block_expr5.rs @@ -0,0 +1,40 @@ +fn foo() -> i32 { + 0 +} + +fn bar() -> i32 { + foo(); + foo() +} + +fn baz() -> i32 { + { + bar(); + bar(); + } + { + bar(); + bar() + }; + { + bar(); + bar() + } +} + +fn test(ok: i32) -> i32 { + if ok >= 1 { + foo() + } else if ok <= -1 { + bar() + } else { + baz() + } +} + +fn main() { + let a = foo(); + let b = bar(); + let c = baz(); + test(a + b + c); +} diff --git a/gcc/testsuite/rust/compile/torture/block_expr_parser_bug.rs b/gcc/testsuite/rust/compile/torture/block_expr_parser_bug.rs new file mode 100644 index 00000000000..468aace9881 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/block_expr_parser_bug.rs @@ -0,0 +1,5 @@ +fn main() { + let a = 123; + let b = if a > 10 { a - 1 } else { a + 1 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/bom.rs b/gcc/testsuite/rust/compile/torture/bom.rs new file mode 100644 index 00000000000..5edcab227ee --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/bom.rs @@ -0,0 +1 @@ +pub fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/bom_comment.rs b/gcc/testsuite/rust/compile/torture/bom_comment.rs new file mode 100644 index 00000000000..020e1707b55 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/bom_comment.rs @@ -0,0 +1,2 @@ +// UTF8 BOM +pub fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/bom_shebang.rs b/gcc/testsuite/rust/compile/torture/bom_shebang.rs new file mode 100644 index 00000000000..4c552e8d71d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/bom_shebang.rs @@ -0,0 +1,2 @@ +#!/usr/bin/cat +pub fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/bom_whitespace.rs b/gcc/testsuite/rust/compile/torture/bom_whitespace.rs new file mode 100644 index 00000000000..b10d5654473 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/bom_whitespace.rs @@ -0,0 +1,2 @@ + +pub fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/bools_eq.rs b/gcc/testsuite/rust/compile/torture/bools_eq.rs new file mode 100644 index 00000000000..965127b5d54 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/bools_eq.rs @@ -0,0 +1,18 @@ +extern "C" +{ + fn abort (); +} + +fn beq (a: bool, b: bool) -> bool +{ + let bools_eq = a == b; + bools_eq +} + +pub fn main () +{ + let a = true; + let b = false; + let r = beq (a, b); + if r { unsafe { abort (); } } +} diff --git a/gcc/testsuite/rust/compile/torture/borrow1.rs b/gcc/testsuite/rust/compile/torture/borrow1.rs new file mode 100644 index 00000000000..8afa4746fef --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/borrow1.rs @@ -0,0 +1,17 @@ +fn main() { + let a: i32; + a = 123; + + let b: &i32; + b = &a; + + let aa; + aa = 456; + let bb: &_; + bb = &a; + + let aaa; + aaa = 123; + let bbb; + bbb = &aaa; +} diff --git a/gcc/testsuite/rust/compile/torture/borrow_function.rs b/gcc/testsuite/rust/compile/torture/borrow_function.rs new file mode 100644 index 00000000000..98c6f99683e --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/borrow_function.rs @@ -0,0 +1,5 @@ +fn foo() {} + +fn main() { + let _a = &foo; +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/break_function.rs b/gcc/testsuite/rust/compile/torture/break_function.rs new file mode 100644 index 00000000000..043e91c9502 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/break_function.rs @@ -0,0 +1,10 @@ +fn foo() -> i32 { + 1 +} + +fn main() { + let _a = loop { + break foo(); + }; +} + \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/byte_char_str.rs b/gcc/testsuite/rust/compile/torture/byte_char_str.rs new file mode 100644 index 00000000000..bc3ec5014e8 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/byte_char_str.rs @@ -0,0 +1,8 @@ +pub fn main () +{ + let _c = 'x'; + let _bc = b'x'; + + let _s = "abc"; + let _bs = b"abc"; +} diff --git a/gcc/testsuite/rust/compile/torture/byte_str.rs b/gcc/testsuite/rust/compile/torture/byte_str.rs new file mode 100644 index 00000000000..28934d2581d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/byte_str.rs @@ -0,0 +1,4 @@ +pub fn main() { + let a: &[u8; 4]; + a = b"test"; +} diff --git a/gcc/testsuite/rust/compile/torture/cast1.rs b/gcc/testsuite/rust/compile/torture/cast1.rs new file mode 100644 index 00000000000..845d08cea01 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/cast1.rs @@ -0,0 +1,5 @@ +fn main() { + let a: *const i32 = &123; + let b: *mut i32 = (a as *mut i32); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/cast2.rs b/gcc/testsuite/rust/compile/torture/cast2.rs new file mode 100644 index 00000000000..82925e93271 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/cast2.rs @@ -0,0 +1,5 @@ +fn main() { + let a: i32 = 123i32; + let b: u8 = a as u8; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/cast3.rs b/gcc/testsuite/rust/compile/torture/cast3.rs new file mode 100644 index 00000000000..1de95687039 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/cast3.rs @@ -0,0 +1,6 @@ +fn main() { + let a = "foo\0"; + let b = a as *const str; + let c = b as *const i8; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/cfg_attr.rs b/gcc/testsuite/rust/compile/torture/cfg_attr.rs new file mode 100644 index 00000000000..d65faf2972a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/cfg_attr.rs @@ -0,0 +1,7 @@ +mod fake {} // Add one line so gccrs doesn't believe we're parsing a shebang + +#[cfg_attr(feature = "somefeature", attribute = "someattr")] +struct Feature; +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +fn main() {} diff --git a/gcc/testsuite/rust/compile/torture/char1.rs b/gcc/testsuite/rust/compile/torture/char1.rs new file mode 100644 index 00000000000..73835c218a2 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/char1.rs @@ -0,0 +1,4 @@ +fn main() { + let a; + a = 'c'; +} diff --git a/gcc/testsuite/rust/compile/torture/check-doc-attr-string.rs b/gcc/testsuite/rust/compile/torture/check-doc-attr-string.rs new file mode 100644 index 00000000000..e113120bdbc --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/check-doc-attr-string.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] + +#[doc(alias = "foo")] // ok! +#[doc(alias("bar", "baz"))] // ok! +pub struct Bar; + +#[doc(alias = " +")] // { dg-error "invalid character used" "" { target *-*-* } .-1 } +pub struct Foo; + +#[doc(alias( + " +" +))] // ko but unchecked for now +pub struct Foo2; + +#[doc(whatever = "buidule")] // ko as well but unchecked for now +struct Boo; diff --git a/gcc/testsuite/rust/compile/torture/coercion1.rs b/gcc/testsuite/rust/compile/torture/coercion1.rs new file mode 100644 index 00000000000..3bfa938ffdc --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/coercion1.rs @@ -0,0 +1,11 @@ +pub fn main() { + let a: &i32 = &123; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b: &mut i32 = &mut 123; + + let c: &i32 = &mut 123; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let d: &i32 = b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/coercion2.rs b/gcc/testsuite/rust/compile/torture/coercion2.rs new file mode 100644 index 00000000000..127f257f8b6 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/coercion2.rs @@ -0,0 +1,20 @@ +pub fn main() { + let a: *const i32 = &123; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b: &i32 = &123; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let c: &mut i32 = &mut 123; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let d: *mut i32 = &mut 123; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let e: &i32 = &mut 123; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let f: *const i32 = &mut 123; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let g = &123; + let h: *const i32 = g; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/comparison_expr1.rs b/gcc/testsuite/rust/compile/torture/comparison_expr1.rs new file mode 100644 index 00000000000..ed71ec89025 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/comparison_expr1.rs @@ -0,0 +1,38 @@ +fn is_zero(x: i32) -> bool { + x == 0 +} + +fn is_not_zero(x: i32) -> bool { + x != 0 +} + +fn is_positive(x: i32) -> bool { + x > 0 +} + +fn is_negative(x: i32) -> bool { + x < 0 +} + +fn is_positive_or_zero(x: i32) -> bool { + x >= 0 +} + +fn is_negative_or_zero(x: i32) -> bool { + x <= 0 +} + +fn main() { + let a: bool = is_zero(1); + let b: bool = is_not_zero(2); + let c: bool = is_positive(3); + let d: bool = is_negative(4); + let e: bool = is_positive_or_zero(5); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let f: bool = is_negative_or_zero(6); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let g: bool = a || b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let h: bool = c && d; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/compile.exp b/gcc/testsuite/rust/compile/torture/compile.exp new file mode 100644 index 00000000000..48da264a47a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/compile.exp @@ -0,0 +1,33 @@ +# Copyright (C) 2021-2022 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 +# . + +# Compile tests, torture testing. + +# Load support procs. +load_lib rust-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +set saved-dg-do-what-default ${dg-do-what-default} + +set dg-do-what-default "compile" +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" "" +set dg-do-what-default ${saved-dg-do-what-default} + +# All done. +dg-finish diff --git a/gcc/testsuite/rust/compile/torture/compound_assignment_expr1.rs b/gcc/testsuite/rust/compile/torture/compound_assignment_expr1.rs new file mode 100644 index 00000000000..1ff0d24cf8e --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/compound_assignment_expr1.rs @@ -0,0 +1,23 @@ +fn main() { + let mut a = 1; + let mut b = 2; + let mut c = 3; + let mut d = 4; + let mut e = 5; + let mut f = 6; + let mut g = 7; + let mut h = 8; + let mut i = 9; + let mut j = 10; + + a += 1; + b -= 2; + c *= 3; + d /= 4; + e %= 5; + f &= 6; + g |= 7; + h ^= 8; + i <<= 9; + j >>= 10; +} diff --git a/gcc/testsuite/rust/compile/torture/conditional.rs b/gcc/testsuite/rust/compile/torture/conditional.rs new file mode 100644 index 00000000000..2bb3a95f033 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/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/compile/torture/constant1.rs b/gcc/testsuite/rust/compile/torture/constant1.rs new file mode 100644 index 00000000000..57bcb0b4970 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/constant1.rs @@ -0,0 +1,9 @@ +const TEST_CONST:i32 = 10; + +fn main() { + let mut x = TEST_CONST; + x = x + 1; + + let mut y = x + TEST_CONST; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/constant2.rs b/gcc/testsuite/rust/compile/torture/constant2.rs new file mode 100644 index 00000000000..d06324e8e65 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/constant2.rs @@ -0,0 +1,6 @@ +fn main() { + const C: usize = 42; + + let _a = C; + let _b: [i32; C] = [0; C]; +} diff --git a/gcc/testsuite/rust/compile/torture/constant3.rs b/gcc/testsuite/rust/compile/torture/constant3.rs new file mode 100644 index 00000000000..d2f1dd5b6db --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/constant3.rs @@ -0,0 +1,10 @@ +fn main() { + const A: [i32; 3] = [1, 2, 3]; + const B: i32 = A[1]; + const C: usize = 42; + const D: i32 = 7; + + let _a = C; + let _b: [i32; C] = [0; C]; + let _c = B + D; +} diff --git a/gcc/testsuite/rust/compile/torture/deadcode1.rs b/gcc/testsuite/rust/compile/torture/deadcode1.rs new file mode 100644 index 00000000000..1ba646f5c56 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/deadcode1.rs @@ -0,0 +1,22 @@ +fn test1() -> i32 { + return 2; + // { dg-warning "unreachable expression" "" { target *-*-* } .+1 } + 1 +} + +fn test2(x: i32) -> i32 { + if x > 1 { + return 5; + } else { + return 0; + } + // { dg-warning "unreachable statement" "" { target *-*-* } .+1 } + return 1; +} + +fn main() { + let call1 = test1(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let call2 = test2(2); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/deadcode2.rs b/gcc/testsuite/rust/compile/torture/deadcode2.rs new file mode 100644 index 00000000000..ba7d5f015e9 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/deadcode2.rs @@ -0,0 +1,10 @@ +fn foo() -> i32 { + return 1; + + let a = -1; // { dg-warning "unreachable statement" } + a // { dg-warning "unreachable expression" } +} + +fn main() { + foo(); +} diff --git a/gcc/testsuite/rust/compile/torture/deref1.rs b/gcc/testsuite/rust/compile/torture/deref1.rs new file mode 100644 index 00000000000..d715ce96c79 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/deref1.rs @@ -0,0 +1,6 @@ +fn main() { + let a = 123; + let b = &a; + let c = *b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/deref_function.rs b/gcc/testsuite/rust/compile/torture/deref_function.rs new file mode 100644 index 00000000000..b1c5ff63423 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/deref_function.rs @@ -0,0 +1,10 @@ +fn foo() {} + + +fn main() { + let _c = *{ + let _a = foo; + let b = &1; + b + }; +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/doc_comment.rs b/gcc/testsuite/rust/compile/torture/doc_comment.rs new file mode 100644 index 00000000000..f99e41524ae --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/doc_comment.rs @@ -0,0 +1,16 @@ +/// doc comment 1 +/// doc comment 2 +/// `blah blah` markdown +pub struct TestStruct {} + +#[doc(hidden)] +pub struct DocAttribute {} + +#[doc(a,b)] +pub struct UnkAttribute {} + +fn main() { + let _ = TestStruct {}; + let _ = DocAttribute {}; + let _ = UnkAttribute {}; +} diff --git a/gcc/testsuite/rust/compile/torture/enum1.rs b/gcc/testsuite/rust/compile/torture/enum1.rs new file mode 100644 index 00000000000..7cea48f29e2 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/enum1.rs @@ -0,0 +1,13 @@ +enum Foo { + A, + B, + C(char), + D { x: i64, y: i64 }, +} + +fn main() { + let _a = Foo::A; + let _b = Foo::B; + let _c = Foo::C('x'); + let _d = Foo::D { x: 20, y: 80 }; +} diff --git a/gcc/testsuite/rust/compile/torture/extern_mod1.rs b/gcc/testsuite/rust/compile/torture/extern_mod1.rs new file mode 100644 index 00000000000..4b576e03d80 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/extern_mod1.rs @@ -0,0 +1,6 @@ +// { dg-additional-options "-w" } +mod modules; + +fn main() { + let twelve = modules::return_12(); +} diff --git a/gcc/testsuite/rust/compile/torture/extern_mod2.rs b/gcc/testsuite/rust/compile/torture/extern_mod2.rs new file mode 100644 index 00000000000..4984d5dc2c1 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/extern_mod2.rs @@ -0,0 +1,23 @@ +// { dg-additional-options "-w" } + +#[path = "modules/valid_path.rs"] +mod not_a_valid_path; + +#[path ="modules/valid_path.rs"] +mod path_without_extra_equal; + +#[path= "modules/valid_path.rs"] +mod no_leading_equal; + +#[path = "modules/valid_path.rs"] +mod extra_spaces; + +#[path] // { dg-error "path attributes must contain a filename" } +mod error; // { dg-error "no candidate found" } + +// This is "valid", and should only error out when parsing +// the file +#[path = "not_a_valid_file.rs"] +mod another_error; // { dg-error "No such file or directory" } + +fn main() {} diff --git a/gcc/testsuite/rust/compile/torture/float1.rs b/gcc/testsuite/rust/compile/torture/float1.rs new file mode 100644 index 00000000000..fbe89382267 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/float1.rs @@ -0,0 +1,9 @@ +fn test(x: f32) -> f32 { + return x + 1.0; +} + +fn main() { + let a_float = 5.123; + let call_test = test(a_float + 1.0); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/float_types.rs b/gcc/testsuite/rust/compile/torture/float_types.rs new file mode 100644 index 00000000000..7d3d298a1bb --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/float_types.rs @@ -0,0 +1,13 @@ +// { dg-prune-output "warning: unused name" } as there are many of these expected. + +fn main() { + let a1: f32 = 1.0f32; + let a2: f64 = 2.0f64; + let a3: f32 = 3f32; + let a4: f64 = 4f64; + + let b1 = 1.0f32; + let b2 = 2.0f64; + let b3 = 3f32; + let b4 = 4f64; +} diff --git a/gcc/testsuite/rust/compile/torture/forward_decl_1.rs b/gcc/testsuite/rust/compile/torture/forward_decl_1.rs new file mode 100644 index 00000000000..b8403f9b97f --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/forward_decl_1.rs @@ -0,0 +1,11 @@ +fn main() { + let mut an_integer = 5; + an_integer = test(1) + 3; + + let call_test = test(1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +fn test(x: i32) -> i32 { + return x + 1; +} diff --git a/gcc/testsuite/rust/compile/torture/forward_decl_2.rs b/gcc/testsuite/rust/compile/torture/forward_decl_2.rs new file mode 100644 index 00000000000..efc3b0dc565 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/forward_decl_2.rs @@ -0,0 +1,6 @@ +fn main() { + let y = x + 1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +static x: i32 = 3; diff --git a/gcc/testsuite/rust/compile/torture/forward_decl_3-unsafe.rs b/gcc/testsuite/rust/compile/torture/forward_decl_3-unsafe.rs new file mode 100644 index 00000000000..04935864f02 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/forward_decl_3-unsafe.rs @@ -0,0 +1,13 @@ +fn main() { + unsafe { + let struct_test = Foo { one: 1, two: 2 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + }; +} + +struct Foo { + one: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + two: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/forward_decl_3.rs b/gcc/testsuite/rust/compile/torture/forward_decl_3.rs new file mode 100644 index 00000000000..9256df5f728 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/forward_decl_3.rs @@ -0,0 +1,11 @@ +fn main() { + let struct_test = Foo { one: 1, two: 2 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +struct Foo { + one: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + two: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/forward_decl_4.rs b/gcc/testsuite/rust/compile/torture/forward_decl_4.rs new file mode 100644 index 00000000000..e1fe51f9025 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/forward_decl_4.rs @@ -0,0 +1,9 @@ +fn main() { + let mut x = TEST_CONST; + x = x + 1; + + let mut y = x + TEST_CONST; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +const TEST_CONST: i32 = 10; diff --git a/gcc/testsuite/rust/compile/torture/forward_decl_5.rs b/gcc/testsuite/rust/compile/torture/forward_decl_5.rs new file mode 100644 index 00000000000..73a47fe061b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/forward_decl_5.rs @@ -0,0 +1,19 @@ +pub fn main() { + let a; + a = foo { a: 123, b: 456f32 }; + + let mut a = 123; + a = bar(a); + + let mut b = 456f32; + b = bar(b); + + fn bar(x: T) -> T { + x + } + + struct foo { + a: i32, + b: f32, + }; +} diff --git a/gcc/testsuite/rust/compile/torture/func1.rs b/gcc/testsuite/rust/compile/torture/func1.rs new file mode 100644 index 00000000000..df1789e7bbe --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/func1.rs @@ -0,0 +1,7 @@ +fn not_void() -> i32 { + 8 +} + +fn main() { + not_void(); +} diff --git a/gcc/testsuite/rust/compile/torture/func2.rs b/gcc/testsuite/rust/compile/torture/func2.rs new file mode 100644 index 00000000000..f7dd556d955 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/func2.rs @@ -0,0 +1,20 @@ +fn foo() { + 8; + 8; +} + +fn bar() -> i32 { + 8; + 8 +} + +fn baz() -> i32 { + 8; + return 8; +} + +fn main() { + let a = foo(); // { dg-warning "unused name" } + let b = bar(); // { dg-warning "unused name" } + let c = baz(); // { dg-warning "unused name" } +} diff --git a/gcc/testsuite/rust/compile/torture/function_reference1.rs b/gcc/testsuite/rust/compile/torture/function_reference1.rs new file mode 100644 index 00000000000..dfbd01bdbdc --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/function_reference1.rs @@ -0,0 +1,9 @@ +fn test(a: i32) -> i32 { + a + 1 +} + +fn main() { + let a = test; + let b = a(1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/function_reference2.rs b/gcc/testsuite/rust/compile/torture/function_reference2.rs new file mode 100644 index 00000000000..3c3e7c10910 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/function_reference2.rs @@ -0,0 +1,9 @@ +fn test(a: i32) -> i32 { + a + 1 +} + +fn main() { + let a: fn(i32) -> i32 = test; + let b = a(1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/function_reference3.rs b/gcc/testsuite/rust/compile/torture/function_reference3.rs new file mode 100644 index 00000000000..0cb3181f4a1 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/function_reference3.rs @@ -0,0 +1,20 @@ +struct Foo { + a: fn(i32) -> i32, + b: i32, +} + +fn test(a: i32) -> i32 { + a + 1 +} + +fn main() { + let a = test(1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let b: fn(i32) -> i32 = test; + let c = b(1); + + let d = Foo { a: test, b: c }; + let e = (d.a)(d.b); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/function_reference4.rs b/gcc/testsuite/rust/compile/torture/function_reference4.rs new file mode 100644 index 00000000000..977e4c97215 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/function_reference4.rs @@ -0,0 +1,9 @@ +fn test(a: i32) -> i32 { + a + 1 +} + +fn main() { + let a: fn(_) -> _ = test; + let b = a(1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics1.rs b/gcc/testsuite/rust/compile/torture/generics1.rs new file mode 100644 index 00000000000..87bcdc8f305 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics1.rs @@ -0,0 +1,51 @@ +struct Foo { + a: f32, + b: bool, +} + +struct GenericStruct { + a: T, + b: usize, +} + +fn main() { + let a1; + a1 = Foo { a: 1.0, b: false }; + + let b1: f32 = a1.a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c1: bool = a1.b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a2: GenericStruct; + a2 = GenericStruct:: { a: 1, b: 456 }; + + let b2: i8 = a2.a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c2: usize = a2.b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a3; + a3 = GenericStruct:: { a: 123, b: 456 }; + + let b3: i32 = a3.a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c3: usize = a3.b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a4; + a4 = GenericStruct { a: 1.0, b: 456 }; + + let b4: f32 = a4.a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c4: usize = a4.b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a5; + a5 = GenericStruct::<_> { a: true, b: 456 }; + + let b5: bool = a5.a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c5: usize = a5.b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics10.rs b/gcc/testsuite/rust/compile/torture/generics10.rs new file mode 100644 index 00000000000..8473d49587b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics10.rs @@ -0,0 +1,20 @@ +struct Foo(T); + +struct Bar { + a: Foo, + b: bool, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn test(a: Bar) -> Foo { + a.a +} + +fn main() { + let a: Bar = Bar:: { + a: Foo::(123), + b: true, + }; + let b: Foo = test(a); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics11.rs b/gcc/testsuite/rust/compile/torture/generics11.rs new file mode 100644 index 00000000000..3c8f5ba0058 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics11.rs @@ -0,0 +1,8 @@ +struct Foo(T, u32); + +type TypeAlias = Foo; + +fn main() { + let a: Foo; + a = TypeAlias { 0: 123, 1: 456 }; +} diff --git a/gcc/testsuite/rust/compile/torture/generics12.rs b/gcc/testsuite/rust/compile/torture/generics12.rs new file mode 100644 index 00000000000..f31be584e09 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics12.rs @@ -0,0 +1,17 @@ +struct GenericStruct(T, usize); + +impl GenericStruct { + fn new(a: i32, b: usize) -> Self { + GenericStruct(a, b) + } + + fn get(self) -> i32 { + self.0 + } +} + +fn main() { + let a: GenericStruct = GenericStruct::::new(123, 456); + let aa: i32 = a.get(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics13.rs b/gcc/testsuite/rust/compile/torture/generics13.rs new file mode 100644 index 00000000000..9eb598f02a8 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics13.rs @@ -0,0 +1,41 @@ +struct Foo { + a: A, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +struct GenericStruct { + a: T, + b: usize, +} + +impl Foo { + fn test() -> i32 { + 123 + } + + fn bar(self) -> isize { + // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } + self.a + } +} + +fn main() { + let a: i32 = Foo::test(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a2: GenericStruct; + a2 = GenericStruct:: { a: 1, b: 456 }; + + let b2: i8 = a2.a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c2: usize = a2.b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a4; + a4 = GenericStruct { a: 1.0, b: 456 }; + + let b4: f32 = a4.a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c4: usize = a4.b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics14.rs b/gcc/testsuite/rust/compile/torture/generics14.rs new file mode 100644 index 00000000000..e51a4079e30 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics14.rs @@ -0,0 +1,20 @@ +struct Foo { + a: A, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +impl Foo { + fn test() -> i32 { + 123 + } + + fn bar(self) -> isize { + // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } + self.a + } +} + +fn main() { + let a: i32 = Foo::test(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics15.rs b/gcc/testsuite/rust/compile/torture/generics15.rs new file mode 100644 index 00000000000..c16a67c4dd5 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics15.rs @@ -0,0 +1,23 @@ +struct Foo(T, bool); + +impl Foo { + fn bar(self) -> i32 { + self.0 + } +} + +impl Foo { + fn bar(self) -> f32 { + self.0 + } +} + +fn main() { + let a = Foo(123, true); + let aa = a.bar(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let b = Foo(456f32, true); + let bb = b.bar(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics16.rs b/gcc/testsuite/rust/compile/torture/generics16.rs new file mode 100644 index 00000000000..15b9d7b55e7 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics16.rs @@ -0,0 +1,31 @@ +struct Foo(T, bool); + +impl Foo { + fn new() -> Self { + Foo(123, true) + } + + fn bar(self) -> i32 { + self.0 + } +} + +impl Foo { + fn new() -> Self { + Foo(123f32, true) + } + + fn bar(self) -> f32 { + self.0 + } +} + +fn main() { + let a = Foo::::new(); + let aa: i32 = a.bar(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let b = Foo::::new(); + let bb: f32 = b.bar(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics17.rs b/gcc/testsuite/rust/compile/torture/generics17.rs new file mode 100644 index 00000000000..d52314999b9 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics17.rs @@ -0,0 +1,19 @@ +struct Foo(T); + +impl Foo { + fn new(a: X) -> Self { + Self(a) + } + + fn test(self) -> X { + self.0 + } +} + +fn main() { + let a; + a = Foo::new(123); + + let b = a.test(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics18.rs b/gcc/testsuite/rust/compile/torture/generics18.rs new file mode 100644 index 00000000000..4c98b86a1b9 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics18.rs @@ -0,0 +1,20 @@ +struct Foo(T); + +impl Foo { + fn new(a: X) -> Self { + // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } + Self(a) + } + + fn test(self) -> X { + self.0 + } +} + +fn main() { + let a; + a = Foo(123); + + let b = a.test(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics19.rs b/gcc/testsuite/rust/compile/torture/generics19.rs new file mode 100644 index 00000000000..9a5b4cb48dc --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics19.rs @@ -0,0 +1,12 @@ +struct Foo(X, Y); + +impl Foo { + fn new(a: T) -> Self { + Self(123, a) + } +} + +fn main() { + let a; + a = Foo::new(false); +} diff --git a/gcc/testsuite/rust/compile/torture/generics2.rs b/gcc/testsuite/rust/compile/torture/generics2.rs new file mode 100644 index 00000000000..da0ab992243 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics2.rs @@ -0,0 +1,45 @@ +struct Foo(f32, bool); + +struct GenericStruct(T, usize); + +fn main() { + let a1; + a1 = Foo(1.0, false); + + let b1: f32 = a1.0; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c1: bool = a1.1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a2: GenericStruct; + a2 = GenericStruct::(1, 456); + + let b2: i8 = a2.0; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c2: usize = a2.1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a3; + a3 = GenericStruct::(123, 456); + + let b3: i32 = a3.0; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c3: usize = a3.1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a4; + a4 = GenericStruct(1.0, 456); + + let b4: f32 = a4.0; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c4: usize = a4.1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a5; + a5 = GenericStruct::<_>(true, 456); + + let b5: bool = a5.0; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let c5: usize = a5.1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics20.rs b/gcc/testsuite/rust/compile/torture/generics20.rs new file mode 100644 index 00000000000..8fe1cffdf7d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics20.rs @@ -0,0 +1,12 @@ +struct Foo(A, B); + +impl Foo { + fn new(a: T, b: T) -> Self { + Self(a, b) + } +} + +fn main() { + let a; + a = Foo::new(123, 456); +} diff --git a/gcc/testsuite/rust/compile/torture/generics21.rs b/gcc/testsuite/rust/compile/torture/generics21.rs new file mode 100644 index 00000000000..dc4e935cac7 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics21.rs @@ -0,0 +1,13 @@ +fn callee(t: &T) -> i32 { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + 32 +} + +fn caller(t: i32) -> i32 { + callee(&t) +} + +fn main() { + let a; + a = caller(123); +} diff --git a/gcc/testsuite/rust/compile/torture/generics22.rs b/gcc/testsuite/rust/compile/torture/generics22.rs new file mode 100644 index 00000000000..465ebb0f5e1 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics22.rs @@ -0,0 +1,13 @@ +fn callee(t: (T, bool)) -> i32 { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + 32 +} + +fn caller(t: i32) -> i32 { + callee((t, false)) +} + +fn main() { + let a; + a = caller(123); +} diff --git a/gcc/testsuite/rust/compile/torture/generics23.rs b/gcc/testsuite/rust/compile/torture/generics23.rs new file mode 100644 index 00000000000..2169e3649c6 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics23.rs @@ -0,0 +1,6 @@ +struct Foo(A); + +fn main() { + let a: Foo; + a = Foo(123f32); +} diff --git a/gcc/testsuite/rust/compile/torture/generics24.rs b/gcc/testsuite/rust/compile/torture/generics24.rs new file mode 100644 index 00000000000..0de45a8c404 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics24.rs @@ -0,0 +1,34 @@ +struct Foo { + a: A, +} + +impl Foo { + fn bar(self) -> isize { + self.a + } +} + +impl Foo { + fn bar(self) -> char { + // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } + self.a + } +} + +impl Foo { + fn bar(self) { + let a: (isize, char) = self.a; + let b = a.0; + let c = a.1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let aa: Foo = Foo { a: b }; + let bb: isize = aa.bar(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + } +} + +fn main() { + let a = Foo { a: (123, 'a') }; + a.bar(); +} diff --git a/gcc/testsuite/rust/compile/torture/generics25.rs b/gcc/testsuite/rust/compile/torture/generics25.rs new file mode 100644 index 00000000000..e7792e3efb3 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics25.rs @@ -0,0 +1,9 @@ +struct Foo(A, B); + +fn main() { + let a: Foo; + a = Foo::(true, (false, true)); + + let b: (bool, bool); + b = a.1; +} diff --git a/gcc/testsuite/rust/compile/torture/generics26.rs b/gcc/testsuite/rust/compile/torture/generics26.rs new file mode 100644 index 00000000000..522e16f32f7 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics26.rs @@ -0,0 +1,21 @@ +// github issue #415 +fn test(a: A, b: B) -> (A, B) { + (a, b) +} + +fn main() { + let a = test::(123, 456); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let b = test::(123f32, 456f32); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let c = test::<_, _>(123, 456f32); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let d = test(true, 1234); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let e = test((123, false), 123f32); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics27.rs b/gcc/testsuite/rust/compile/torture/generics27.rs new file mode 100644 index 00000000000..9871638dd9f --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics27.rs @@ -0,0 +1,16 @@ +// github issue #415 +fn test(a: &A) -> &A { + a +} + +fn main() { + let a = 123; + let b = &a; + let c = test(b); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a = 123f32; + let b = &a; + let c = test(b); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics28.rs b/gcc/testsuite/rust/compile/torture/generics28.rs new file mode 100644 index 00000000000..8cee8b00fb2 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics28.rs @@ -0,0 +1,18 @@ +struct Foo(A, B); + +impl Foo { + fn test(a: X) -> X { + a + } +} + +fn main() { + let a; + a = Foo::test::<_>(123); + + let b; + b = Foo::test::(true); + + let c; + c = Foo::test(456f32); +} diff --git a/gcc/testsuite/rust/compile/torture/generics29.rs b/gcc/testsuite/rust/compile/torture/generics29.rs new file mode 100644 index 00000000000..e09a1044574 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics29.rs @@ -0,0 +1,16 @@ +struct Foo(A, B); + +impl Foo { + fn test(self, a: X) -> X { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + a + } +} + +fn main() { + let a; + a = Foo(123, 456f32); + + let b; + b = a.test::(false); +} diff --git a/gcc/testsuite/rust/compile/torture/generics3.rs b/gcc/testsuite/rust/compile/torture/generics3.rs new file mode 100644 index 00000000000..ceec8f7d9c6 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics3.rs @@ -0,0 +1,15 @@ +fn test(a: T) -> T { + a +} + +fn main() { + let a; + a = test(123); + let aa: i32 = a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let b; + b = test::(456); + let bb: u32 = b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics30.rs b/gcc/testsuite/rust/compile/torture/generics30.rs new file mode 100644 index 00000000000..229f6d1254b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics30.rs @@ -0,0 +1,16 @@ +struct Foo(A, B); + +impl Foo { + fn test(self, a: X) -> X { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + a + } +} + +fn main() { + let a; + a = Foo(123, 456f32); + + let b; + b = a.test::(false); +} diff --git a/gcc/testsuite/rust/compile/torture/generics31.rs b/gcc/testsuite/rust/compile/torture/generics31.rs new file mode 100644 index 00000000000..68ad4bf9a96 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics31.rs @@ -0,0 +1,15 @@ +struct Foo(A, B); + +impl Foo { + fn test(self, a: X) -> (T, X) { + (self.0, a) + } +} + +fn main() { + let a; + a = Foo(123, 456f32); + + let b; + b = a.test::(false); +} diff --git a/gcc/testsuite/rust/compile/torture/generics32.rs b/gcc/testsuite/rust/compile/torture/generics32.rs new file mode 100644 index 00000000000..21b9cae7409 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics32.rs @@ -0,0 +1,15 @@ +struct Foo(A, B); + +impl Foo { + fn test(self, a: X) -> (T, X) { + (self.0, a) + } +} + +fn main() { + let a; + a = Foo(123, 456f32); + + let b; + b = a.test(false); +} diff --git a/gcc/testsuite/rust/compile/torture/generics4.rs b/gcc/testsuite/rust/compile/torture/generics4.rs new file mode 100644 index 00000000000..915cc49c68b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics4.rs @@ -0,0 +1,17 @@ +struct Foo { + a: T, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } + b: bool, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn test(a: T) -> Foo { + Foo { a: a, b: true } +} + +fn main() { + let a: Foo = test(123); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b: Foo = test(456); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics5.rs b/gcc/testsuite/rust/compile/torture/generics5.rs new file mode 100644 index 00000000000..b7f43028992 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics5.rs @@ -0,0 +1,10 @@ +fn test(a: T) -> T { + a +} + +fn main() { + let a: i32 = test(123); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b: i32 = test(456); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics6.rs b/gcc/testsuite/rust/compile/torture/generics6.rs new file mode 100644 index 00000000000..5456b6dcb97 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics6.rs @@ -0,0 +1,16 @@ +struct Foo(T); + +struct Bar { + a: Foo, + b: bool, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn main() { + let a: Bar = Bar:: { + a: Foo::(123), + b: true, + }; + let b: i32 = a.a.0; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics7.rs b/gcc/testsuite/rust/compile/torture/generics7.rs new file mode 100644 index 00000000000..e8e5ca69c3d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics7.rs @@ -0,0 +1,14 @@ +struct Foo(T); + +struct Bar { + a: Foo, + b: bool, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn main() { + let a = Foo::(123); + let b: Bar = Bar { a: a, b: true }; + let c: i32 = b.a.0; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics8.rs b/gcc/testsuite/rust/compile/torture/generics8.rs new file mode 100644 index 00000000000..036d85568f0 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics8.rs @@ -0,0 +1,18 @@ +struct GenericStruct(T, usize); + +impl GenericStruct { + fn new(a: T, b: usize) -> Self { + GenericStruct(a, b) + } +} + +fn main() { + let a: GenericStruct = GenericStruct::::new(123, 456); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let b: GenericStruct = GenericStruct::<_>::new(123, 456); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let c: GenericStruct = GenericStruct::new(123f32, 456); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/generics9.rs b/gcc/testsuite/rust/compile/torture/generics9.rs new file mode 100644 index 00000000000..307c34f3e9b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/generics9.rs @@ -0,0 +1,25 @@ +struct GenericStruct(T, usize); + +impl GenericStruct { + fn new(a: T, b: usize) -> Self { + GenericStruct(a, b) + } + + fn get(self) -> T { + self.0 + } +} + +fn main() { + let a: GenericStruct = GenericStruct::::new(123, 456); + let aa: i32 = a.get(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let b: GenericStruct = GenericStruct::<_>::new(123, 456); + let bb: u32 = b.get(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let c: GenericStruct = GenericStruct::new(123f32, 456); + let cc: f32 = c.get(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/grouped_expr_function.rs b/gcc/testsuite/rust/compile/torture/grouped_expr_function.rs new file mode 100644 index 00000000000..eca7178b7f7 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/grouped_expr_function.rs @@ -0,0 +1,6 @@ +fn foo() {} + + +fn main() { + let _a = (foo()); +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/identifier-missing-impl-1.rs b/gcc/testsuite/rust/compile/torture/identifier-missing-impl-1.rs new file mode 100644 index 00000000000..2389fa52bfd --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/identifier-missing-impl-1.rs @@ -0,0 +1,19 @@ +struct I(); + +impl I { + fn () { + // { dg-error {expecting 'identifier' but '\(' found} "" { target *-*-* } .-1 } + // { dg-error {failed to parse inherent impl item in inherent impl} "" { target *-*-* } .-2 } + // { dg-error {failed to parse item in crate} "" { target *-*-* } .-3 } + } +} + +impl I { + unsafe fn () { + // { dg-error {expecting 'identifier' but '\(' found} "" { xfail *-*-* } .-1 } + } +} + +fn main() { + let _i = I(); +} diff --git a/gcc/testsuite/rust/compile/torture/if.rs b/gcc/testsuite/rust/compile/torture/if.rs new file mode 100644 index 00000000000..bcd520f66a9 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/if.rs @@ -0,0 +1,19 @@ +fn foo() -> bool { + true +} + +fn bar() {} + +struct Foo1 { + one: i32 +} + + +fn main() { + if foo() { + bar(); + let a = Foo1{one: 1}; + a.one + } + +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/if_elif.rs b/gcc/testsuite/rust/compile/torture/if_elif.rs new file mode 100644 index 00000000000..a89ad5eb02f --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/if_elif.rs @@ -0,0 +1,20 @@ +fn foo() -> bool { + true +} + +fn bar() -> bool { + false +} + +struct Foo1 { + one: i32 +} + + +fn main() { + if foo() { + } else if bar() { + let a = Foo1{one: 1}; + a.one; + } +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/if_elif_else_expr1.rs b/gcc/testsuite/rust/compile/torture/if_elif_else_expr1.rs new file mode 100644 index 00000000000..65ed7f7a23a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/if_elif_else_expr1.rs @@ -0,0 +1,14 @@ +fn test(x: i32) -> i32 { + if x == 10 { + 123 + } else if x < 10 { + 456 + } else { + 789 + } +} + +fn main() { + let a = test(1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/if_else.rs b/gcc/testsuite/rust/compile/torture/if_else.rs new file mode 100644 index 00000000000..09aecaed4d6 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/if_else.rs @@ -0,0 +1,19 @@ +fn foo() -> bool { + true +} + +fn bar() {} + +struct Foo1 { + one: i32 +} + + +fn main() { + if foo() { + bar(); + } else { + let a = Foo1{one: 1}; + a.one; + } +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/ifunaryexpr.rs b/gcc/testsuite/rust/compile/torture/ifunaryexpr.rs new file mode 100644 index 00000000000..8f0bb87f558 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/ifunaryexpr.rs @@ -0,0 +1,22 @@ +extern "C" +{ + pub fn abort (); +} + +struct B { b: bool } + +pub fn main () +{ + let n = 1; + if 0 > -n { } else { unsafe { abort (); } } + + let b = true; + if !b { unsafe { abort (); } } + if !!b { } else { unsafe { abort (); } } + + let bb = B { b: false }; + + if !bb.b && !b { unsafe { abort (); } } + + if (B { b: true }).b { } else { unsafe { abort (); } } +} diff --git a/gcc/testsuite/rust/compile/torture/impl_block1.rs b/gcc/testsuite/rust/compile/torture/impl_block1.rs new file mode 100644 index 00000000000..d67afa187b1 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/impl_block1.rs @@ -0,0 +1,23 @@ +struct Foo(i32, bool); + +impl Foo { + fn new(a: i32, b: bool) -> Foo { + Foo(a, b) + } + + fn test2() -> i32 { + test_forward_decl() + } +} + +fn test_forward_decl() -> i32 { + 123 +} + +fn main() { + let a; + a = Foo::new(1, true); + + let b; + b = Foo::test2(); +} diff --git a/gcc/testsuite/rust/compile/torture/impl_block2.rs b/gcc/testsuite/rust/compile/torture/impl_block2.rs new file mode 100644 index 00000000000..0ed592d07be --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/impl_block2.rs @@ -0,0 +1,28 @@ +struct Foo(i32, bool); + +impl Foo { + const number: i32 = 456; + + fn new(a: i32, b: bool) -> Foo { + Foo(a, b) + } + + fn test2() -> i32 { + test_forward_decl() + } +} + +fn test_forward_decl() -> i32 { + 123 +} + +fn main() { + let a; + a = Foo::new(1, true); + + let b; + b = Foo::test2(); + + let c; + c = Foo::new(Foo::number, true); +} diff --git a/gcc/testsuite/rust/compile/torture/impl_block3.rs b/gcc/testsuite/rust/compile/torture/impl_block3.rs new file mode 100644 index 00000000000..22ce19f704d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/impl_block3.rs @@ -0,0 +1,36 @@ +struct Point { + x: f64, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } + y: f64, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +impl Point { + fn origin() -> Point { + Point { x: 0.0, y: 0.0 } + } + + fn new(x: f64, y: f64) -> Point { + Point { x: x, y: y } + } +} + +struct Rectangle { + p1: Point, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } + p2: Point, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +impl Rectangle { + fn from(p1: Point, p2: Point) -> Self { + Self { p1, p2 } + } +} + +fn main() { + let p1 = Point::origin(); + let p2 = Point::new(3.0, 4.0); + let rect = Rectangle::from(p1, p2); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/impl_block_unused.rs b/gcc/testsuite/rust/compile/torture/impl_block_unused.rs new file mode 100644 index 00000000000..fea86319243 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/impl_block_unused.rs @@ -0,0 +1,17 @@ +struct Foo(i32, bool); + +impl Foo { + fn new(a: i32, b: bool) -> Foo { + // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } + Foo(a, b) + } + + fn test2() -> i32 { + // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } + 1 + } +} + +fn main() { + let _a = Foo(1, true); +} diff --git a/gcc/testsuite/rust/compile/torture/implicit_returns1.rs b/gcc/testsuite/rust/compile/torture/implicit_returns1.rs new file mode 100644 index 00000000000..54cc8b3aea8 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/implicit_returns1.rs @@ -0,0 +1,73 @@ +fn test1() -> i32 { + 1 +} + +fn test2() -> i32 { + return 2; +} + +fn test3(x: i32) -> i32 { + if x > 1 { + 5 + } else { + 0 + } +} + +fn test4(x: i32) -> i32 { + if x > 1 { + return 1; + } + 0 +} + +fn test5(x: i32) -> i32 { + if x > 1 { + if x == 5 { + 7 + } else { + 9 + } + } else { + 0 + } +} + +fn test6(x: i32) -> i32 { + if x > 1 { + return 5; + } else { + return 0; + } +} + +fn test7(x: i32) -> i32 { + if x > 1 { + return 5; + } else { + return 0; + } +} + +fn test8() -> i32 { + return 1; +} + +fn main() { + let call1 = test1(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let call2 = test2(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let call3 = test3(3); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let call4 = test4(4); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let call5 = test5(5); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let call6 = test6(6); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let call7 = test7(7); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let call8 = test8(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/infer_type1.rs b/gcc/testsuite/rust/compile/torture/infer_type1.rs new file mode 100644 index 00000000000..aabfcef895b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/infer_type1.rs @@ -0,0 +1,4 @@ +fn main() { + let array: [_; 2] = [111, 222]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/inner_attributes.rs b/gcc/testsuite/rust/compile/torture/inner_attributes.rs new file mode 100644 index 00000000000..3410dd6ec87 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/inner_attributes.rs @@ -0,0 +1,3 @@ +#![allow(dead_code)] +#![allow(unused_variables)] +pub fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/integer_inference_var1.rs b/gcc/testsuite/rust/compile/torture/integer_inference_var1.rs new file mode 100644 index 00000000000..ccee06aad10 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/integer_inference_var1.rs @@ -0,0 +1,6 @@ +const TEST_CONST: i32 = 10; + +fn main() { + let a; + a = TEST_CONST; +} diff --git a/gcc/testsuite/rust/compile/torture/integer_inference_var2.rs b/gcc/testsuite/rust/compile/torture/integer_inference_var2.rs new file mode 100644 index 00000000000..2209e937479 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/integer_inference_var2.rs @@ -0,0 +1,6 @@ +fn main() { + let a = 1u32; + + let b; + b = a; +} diff --git a/gcc/testsuite/rust/compile/torture/integer_inference_var3.rs b/gcc/testsuite/rust/compile/torture/integer_inference_var3.rs new file mode 100644 index 00000000000..582ae77caa4 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/integer_inference_var3.rs @@ -0,0 +1,11 @@ +fn test(a: u32) -> u32 { + a + 1 +} + +fn main() { + let param; + param = 123; + + let a = test(param); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/integer_inference_var4.rs b/gcc/testsuite/rust/compile/torture/integer_inference_var4.rs new file mode 100644 index 00000000000..136d8183d08 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/integer_inference_var4.rs @@ -0,0 +1,4 @@ +fn main() { + let a; + a = 1; +} diff --git a/gcc/testsuite/rust/compile/torture/integer_inference_var5.rs b/gcc/testsuite/rust/compile/torture/integer_inference_var5.rs new file mode 100644 index 00000000000..051de1d6520 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/integer_inference_var5.rs @@ -0,0 +1,25 @@ +const TEST_CONST: i32 = 10; + +fn test(x: u32) -> u32 { + x + 1 +} + +fn main() { + let x = TEST_CONST; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let a = 1u32; + let b = a; + + let c; + c = 1; + + let d; + d = b; + + let param; + param = 123; + + let test_call = test(param); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/integer_types.rs b/gcc/testsuite/rust/compile/torture/integer_types.rs new file mode 100644 index 00000000000..95a73780bb1 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/integer_types.rs @@ -0,0 +1,27 @@ +// { dg-prune-output "warning: unused name" } as there are many of these expected. + +fn main() { + let a1: i8 = 1i8; + let a2: i16 = 2i16; + let a3: i32 = 3i32; + let a4: i64 = 4i64; + let a5: i128 = 5i128; + + let b1 = 1i8; + let b2 = 2i16; + let b3 = 3i32; + let b4 = 4i64; + let b5 = 5i128; + + let c1: u8 = 1u8; + let c2: u16 = 2u16; + let c3: u32 = 3u32; + let c4: u64 = 4u64; + let c5: u128 = 5u128; + + let d1 = 1u8; + let d2 = 2u16; + let d3 = 3u32; + let d4 = 4u64; + let d5 = 5u128; +} diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-1.rs b/gcc/testsuite/rust/compile/torture/intrinsics-1.rs new file mode 100644 index 00000000000..6704c0210d1 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/intrinsics-1.rs @@ -0,0 +1,22 @@ +// { dg-additional-options -fdump-tree-original } + +#![feature(intrinsics)] + +extern "rust-intrinsic" { + pub fn sqrtf32(x: f32) -> f32; + pub fn sinf32(x: f32) -> f32; +} + +fn main() { + unsafe fn foo() { + let mut f32; + + f32 = sqrtf32(5f32); + // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_sqrtf \(5\.0e\+0\);$} 1 original } } + + f32 = sinf32(39f32); + // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_sinf \(3\.9e\+1\);$} 1 original } } + } + + unsafe { foo() }; +} diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-2.rs b/gcc/testsuite/rust/compile/torture/intrinsics-2.rs new file mode 100644 index 00000000000..6b2339f38f3 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/intrinsics-2.rs @@ -0,0 +1,22 @@ +// { dg-additional-options -fdump-tree-original } + +#![feature(intrinsics)] + +extern "rust-intrinsic" { + pub fn size_of() -> usize; +} + +fn main() -> i32 { + unsafe fn foo() -> usize { + let f: f32; + + let s_f32 = size_of::(); + let s_f64 = size_of::(); + let s_f32_again = size_of::(); + + s_f32 + s_f64 + s_f32_again + } + + // useless code, just used for function compilation caching + unsafe { foo() as i32 } +} diff --git a/gcc/testsuite/rust/compile/torture/isolated_cr_block_comment.rs b/gcc/testsuite/rust/compile/torture/isolated_cr_block_comment.rs new file mode 100644 index 00000000000..9a1e090f330 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/isolated_cr_block_comment.rs @@ -0,0 +1,2 @@ +/* comment cr is allowed */ +pub fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/isolated_cr_line_comment.rs b/gcc/testsuite/rust/compile/torture/isolated_cr_line_comment.rs new file mode 100644 index 00000000000..4e921a225c2 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/isolated_cr_line_comment.rs @@ -0,0 +1,2 @@ +// comment cr is allowed +pub fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/issue-1024.rs b/gcc/testsuite/rust/compile/torture/issue-1024.rs new file mode 100644 index 00000000000..109540934a8 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/issue-1024.rs @@ -0,0 +1,11 @@ +extern "rust-intrinsic" { + pub fn size_of() -> usize; +} + +fn test() -> usize { + unsafe { size_of::() } +} + +fn main() { + let _a = test(); +} diff --git a/gcc/testsuite/rust/compile/torture/issue-1075.rs b/gcc/testsuite/rust/compile/torture/issue-1075.rs new file mode 100644 index 00000000000..7c0a0434262 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/issue-1075.rs @@ -0,0 +1,42 @@ +// { dg-additional-options "-w" } +extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + pub fn offset(dst: *const T, offset: isize) -> *const T; +} + +struct FatPtr { + data: *const T, + len: usize, +} + +union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +impl *const [T] { + pub const fn len(self) -> usize { + // SAFETY: this is safe because `*const [T]` and `FatPtr` have the same layout. + // Only `std` can make this guarantee. + unsafe { Repr { rust: self }.raw.len } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +impl *const T { + pub const unsafe fn offset(self, count: isize) -> *const T { + unsafe { offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} diff --git a/gcc/testsuite/rust/compile/torture/issue-1432.rs b/gcc/testsuite/rust/compile/torture/issue-1432.rs new file mode 100644 index 00000000000..083a369d16f --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/issue-1432.rs @@ -0,0 +1,77 @@ +// { dg-additional-options "-w" } +mod intrinsics { + extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] + pub fn wrapping_add(a: T, b: T) -> T; + #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] + pub fn rotate_left(a: T, b: T) -> T; + #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] + pub fn rotate_right(a: T, b: T) -> T; + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + pub fn offset(ptr: *const T, count: isize) -> *const T; + } +} + +mod mem { + extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_transmute", since = "1.46.0")] + fn transmute(_: T) -> U; + #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] + fn size_of() -> usize; + } +} + +macro_rules! impl_uint { + ($($ty:ident = $lang:literal),*) => { + $( + impl $ty { + pub fn wrapping_add(self, rhs: Self) -> Self { + // intrinsics::wrapping_add(self, rhs) + self + rhs + } + + pub fn rotate_left(self, n: u32) -> Self { + unsafe { + intrinsics::rotate_left(self, n as Self) + } + } + + pub fn rotate_right(self, n: u32) -> Self { + unsafe { + intrinsics::rotate_right(self, n as Self) + } + } + + pub fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + } + + pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_le(Self::from_ne_bytes(bytes)) + } + + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + } + + pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + unsafe { mem::transmute(bytes) } + } + } + )* + } +} + +impl_uint!( + u8 = "u8", + u16 = "u16", + u32 = "u32", + u64 = "u64", + usize = "usize" +); diff --git a/gcc/testsuite/rust/compile/torture/issue-1434.rs b/gcc/testsuite/rust/compile/torture/issue-1434.rs new file mode 100644 index 00000000000..dc000e942e6 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/issue-1434.rs @@ -0,0 +1,53 @@ +// { dg-options "-w" } +const BLOCK_LEN: usize = 64; + +const IV: [u32; 8] = [ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, +]; + +struct ChunkState { + chaining_value: [u32; 8], + chunk_counter: u64, + block: [u8; BLOCK_LEN], + block_len: u8, + blocks_compressed: u8, + flags: u32, +} + +impl ChunkState { + fn new(key_words: [u32; 8], chunk_counter: u64, flags: u32) -> Self { + Self { + chaining_value: key_words, + chunk_counter, + block: [0; BLOCK_LEN], + block_len: 0, + blocks_compressed: 0, + flags, + } + } +} + +pub struct Hasher { + chunk_state: ChunkState, + key_words: [u32; 8], + cv_stack: [[u32; 8]; 54], // Space for 54 subtree chaining values: + cv_stack_len: u8, // 2^54 * CHUNK_LEN = 2^64 + flags: u32, +} + +impl Hasher { + fn new_internal(key_words: [u32; 8], flags: u32) -> Self { + Self { + chunk_state: ChunkState::new(key_words, 0, flags), + key_words, + cv_stack: [[0; 8]; 54], + cv_stack_len: 0, + flags, + } + } + + /// Construct a new `Hasher` for the regular hash function. + pub fn new() -> Self { + Self::new_internal(IV, 0) + } +} diff --git a/gcc/testsuite/rust/compile/torture/issue-368.rs b/gcc/testsuite/rust/compile/torture/issue-368.rs new file mode 100644 index 00000000000..18bc9bdc62e --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/issue-368.rs @@ -0,0 +1,9 @@ +struct S; + +fn foo(s: S) -> S { + s +} + +fn main() { + let _s: S = foo(S); +} diff --git a/gcc/testsuite/rust/compile/torture/issue-808.rs b/gcc/testsuite/rust/compile/torture/issue-808.rs new file mode 100644 index 00000000000..2e5a81fe516 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/issue-808.rs @@ -0,0 +1,20 @@ +pub trait Foo { + type Target; + + fn bar(&self) -> &Self::Target; +} + +impl Foo for &T { + type Target = T; + + fn bar(&self) -> &T { + *self + } +} + +pub fn main() { + let a: i32 = 123; + let b: &i32 = &a; + + b.bar(); +} diff --git a/gcc/testsuite/rust/compile/torture/issue-862.rs b/gcc/testsuite/rust/compile/torture/issue-862.rs new file mode 100644 index 00000000000..c1a4609ba86 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/issue-862.rs @@ -0,0 +1,74 @@ +// { dg-additional-options "-w" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "imm_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +impl Deref for &mut T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +struct Foo(T); +impl Deref for Foo { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { + let a = "foo_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + &self.0 + } +} + +struct Bar(i32); +impl Bar { + fn cake(self) -> i32 { + self.0 + 1 + } +} + +pub fn main() { + let foo: Foo = Foo(Bar(123)); + let bar: Bar = *foo; + + let cake_result: i32 = foo.cake(); +} diff --git a/gcc/testsuite/rust/compile/torture/issue-893-2.rs b/gcc/testsuite/rust/compile/torture/issue-893-2.rs new file mode 100644 index 00000000000..88a865d66dc --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/issue-893-2.rs @@ -0,0 +1,35 @@ +// { dg-additional-options "-w" } +struct Foo(T); +impl Foo { + fn new(a: T, b: Y) -> Self { + Self(a) + } +} + +struct Bar(T); +impl Bar { + fn baz(self) {} + + fn test() -> i32 { + 123 + } +} + +struct Baz(A, B); +impl Baz { + fn test(a: X) -> X { + a + } +} + +pub fn main() { + let a = Foo::::new::(123, 456f32); + let b = Foo::new::(123, 456f32); + + let c = Bar::(123); + let d = Bar::baz(c); + + let e = Bar::test(); + + let f = Baz::test::(true); +} diff --git a/gcc/testsuite/rust/compile/torture/issue-893.rs b/gcc/testsuite/rust/compile/torture/issue-893.rs new file mode 100644 index 00000000000..d8245f3e0d8 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/issue-893.rs @@ -0,0 +1,11 @@ +// { dg-additional-options "-w" } +struct Foo(T); +impl Foo { + fn new(a: T, b: Y) -> Self { + Self(a) + } +} + +pub fn test() { + let a = Foo::::new::(123, 456f32); +} diff --git a/gcc/testsuite/rust/compile/torture/lazybooleanexpr_function.rs b/gcc/testsuite/rust/compile/torture/lazybooleanexpr_function.rs new file mode 100644 index 00000000000..1be51274d03 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/lazybooleanexpr_function.rs @@ -0,0 +1,14 @@ +fn foo() -> bool { + return true; +} + +fn bar() -> bool { + return false; +} + + + +fn main() { + let _a = true && foo(); + let _b = true || bar(); +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/lifetime1.rs b/gcc/testsuite/rust/compile/torture/lifetime1.rs new file mode 100644 index 00000000000..151fd827b5e --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/lifetime1.rs @@ -0,0 +1,7 @@ +fn foo<'a>(t: &'a str) -> &'a str { + t +} + +fn main() { + foo("hello world"); +} diff --git a/gcc/testsuite/rust/compile/torture/literals1.rs b/gcc/testsuite/rust/compile/torture/literals1.rs new file mode 100644 index 00000000000..cf021e295d2 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/literals1.rs @@ -0,0 +1,11 @@ +// { dg-prune-output "warning: unused name" } as there are many of these expected. + +fn main() { + let hex: i32 = 0xFF; + let binary: i32 = 0b11110000; + let oct: i32 = 0o70; + + let hex_u8: u8 = 0xFF_u8; + let bin_u16: u16 = 0b1111000011110000_u16; + let oct: u32 = 0o70_u32; +} diff --git a/gcc/testsuite/rust/compile/torture/loop1.rs b/gcc/testsuite/rust/compile/torture/loop1.rs new file mode 100644 index 00000000000..a8ee2f59bb8 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/loop1.rs @@ -0,0 +1,10 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + loop { + let c = a + b; + a = b; + b = c; + } +} diff --git a/gcc/testsuite/rust/compile/torture/loop2.rs b/gcc/testsuite/rust/compile/torture/loop2.rs new file mode 100644 index 00000000000..3de3ea81947 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/loop2.rs @@ -0,0 +1,14 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + // first number in Fibonacci sequence over 10: + loop { + if b > 10 { + break; + } + let c = a + b; + a = b; + b = c; + } +} diff --git a/gcc/testsuite/rust/compile/torture/loop3.rs b/gcc/testsuite/rust/compile/torture/loop3.rs new file mode 100644 index 00000000000..76fadfb4337 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/loop3.rs @@ -0,0 +1,14 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + // first number in Fibonacci sequence over 10: + loop { + if b > 10 { + return; + } + let c = a + b; + a = b; + b = c; + } +} diff --git a/gcc/testsuite/rust/compile/torture/loop4.rs b/gcc/testsuite/rust/compile/torture/loop4.rs new file mode 100644 index 00000000000..f7b59357aeb --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/loop4.rs @@ -0,0 +1,7 @@ +fn main() { + 'outer: loop { + 'inner: loop { + break 'outer; + } + } +} diff --git a/gcc/testsuite/rust/compile/torture/loop5.rs b/gcc/testsuite/rust/compile/torture/loop5.rs new file mode 100644 index 00000000000..4004cd30b7b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/loop5.rs @@ -0,0 +1,14 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + // first number in Fibonacci sequence over 10: + let _fib = loop { + if b > 10 { + break b; + } + let c = a + b; + a = b; + b = c; + }; +} diff --git a/gcc/testsuite/rust/compile/torture/loop6.rs b/gcc/testsuite/rust/compile/torture/loop6.rs new file mode 100644 index 00000000000..ecd3ad4fd81 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/loop6.rs @@ -0,0 +1,11 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + let mut c; + while b > 10 { + c = a + b; + a = b; + b = c; + } +} diff --git a/gcc/testsuite/rust/compile/torture/loop7.rs b/gcc/testsuite/rust/compile/torture/loop7.rs new file mode 100644 index 00000000000..0cd844592b6 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/loop7.rs @@ -0,0 +1,13 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + let _fib = loop { + if (a % 2 == 0) { + continue; + } + let c = a + b; + a = b; + b = c; + }; +} diff --git a/gcc/testsuite/rust/compile/torture/macro-issue1403.rs b/gcc/testsuite/rust/compile/torture/macro-issue1403.rs new file mode 100644 index 00000000000..7fe6c51053c --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/macro-issue1403.rs @@ -0,0 +1,23 @@ +macro_rules! stmt { + ($s:stmt) => { + $s + }; + ($s:stmt, $($ss:stmt),*) => { + $s; + stmt!($($ss),*); + }; +} + +fn main() { + stmt!( + struct S; + ); + stmt!( + struct A;, + struct B;, + struct C;, + struct D;, + struct E; + ); +} + diff --git a/gcc/testsuite/rust/compile/torture/macro-issue1426.rs b/gcc/testsuite/rust/compile/torture/macro-issue1426.rs new file mode 100644 index 00000000000..1b558cfa83d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/macro-issue1426.rs @@ -0,0 +1,32 @@ +// { dg-additional-options -fdump-tree-ccp1-raw } + +macro_rules! stmt { + ($s:stmt) => { + $s + }; + ($s:stmt, $($ss:stmt),*) => { + $s; + stmt!($($ss),*); + }; +} + +pub fn test() -> i32 { + stmt!( + let a = 1 + // { dg-warning {unused name 'a'} {} { target *-*-* } .-1 } + ); + stmt!( + let b = 2, + let c = 3, + let d = 4, + let e = 5, + let f = b + c + d + e + ); + f + // { dg-final { scan-tree-dump-times {gimple_return <14>} 1 ccp1 { target __OPTIMIZE__ } } } +} + +fn main() { + let _ = test(); +} + diff --git a/gcc/testsuite/rust/compile/torture/macro_as_expr.rs b/gcc/testsuite/rust/compile/torture/macro_as_expr.rs new file mode 100644 index 00000000000..b0084e7b466 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/macro_as_expr.rs @@ -0,0 +1,14 @@ +// { dg-additional-options "-w" } + +macro_rules! add { + ($a:expr) => { $a }; + ($a:expr, $($b:expr),+) => { $a + add!($($b),*) } +} + +fn main() -> i32 { + if add!(add!(1, 2)) > add!(5) { + add!(1, add!(2, 3), add!(4)) + } else { + add!(5, add!(6, 7), add!(8), 9) + 10 + } +} diff --git a/gcc/testsuite/rust/compile/torture/match1.rs b/gcc/testsuite/rust/compile/torture/match1.rs new file mode 100644 index 00000000000..916b11a3194 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/match1.rs @@ -0,0 +1,16 @@ +// { dg-additional-options "-w" } +enum Foo { + A, + B, + C(char), + D { x: i64, y: i64 }, +} + +fn inspect(f: Foo) { + match f { + Foo::A => {} + Foo::B => {} + Foo::C(x) => {} + Foo::D { x, y } => {} + } +} diff --git a/gcc/testsuite/rust/compile/torture/methods1.rs b/gcc/testsuite/rust/compile/torture/methods1.rs new file mode 100644 index 00000000000..a8e384dabea --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/methods1.rs @@ -0,0 +1,41 @@ +struct Point { + x: f64, + y: f64, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +impl Point { + fn origin() -> Point { + Point { x: 0.0, y: 0.0 } + } + + fn new(x: f64, y: f64) -> Point { + Point { x: x, y: y } + } +} + +struct Rectangle { + p1: Point, + p2: Point, +} + +impl Rectangle { + fn from(p1: Point, p2: Point) -> Self { + Self { p1, p2 } + } + + fn sum_x(self) -> f64 { + let p1 = self.p1; + let p2 = self.p2; + p1.x + p2.x + } +} + +fn main() { + let p1 = Point::origin(); + let p2 = Point::new(3.0, 4.0); + let rect = Rectangle::from(p1, p2); + + let sum = rect.sum_x(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/methods2.rs b/gcc/testsuite/rust/compile/torture/methods2.rs new file mode 100644 index 00000000000..d63211bdf8a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/methods2.rs @@ -0,0 +1,43 @@ +struct Point { + x: f64, + y: f64, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +impl Point { + fn origin() -> Point { + Point { x: 0.0, y: 0.0 } + } + + fn new(x: f64, y: f64) -> Point { + Point { x: x, y: y } + } +} + +struct Rectangle { + p1: Point, + p2: Point, +} + +impl Rectangle { + fn from(p1: Point, p2: Point) -> Self { + Self { p1, p2 } + } +} + +fn main() { + let p1 = Point::origin(); + let p2 = Point::new(3.0, 4.0); + let rect = Rectangle::from(p1, p2); + + let sum = rect.sum_x(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +impl Rectangle { + fn sum_x(self) -> f64 { + let p1 = self.p1; + let p2 = self.p2; + p1.x + p2.x + } +} diff --git a/gcc/testsuite/rust/compile/torture/methods3.rs b/gcc/testsuite/rust/compile/torture/methods3.rs new file mode 100644 index 00000000000..55426f4fcf7 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/methods3.rs @@ -0,0 +1,44 @@ +struct Point { + x: f64, + y: f64, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +impl Point { + fn origin() -> Point { + Point { x: 0.0, y: 0.0 } + } + + fn new(x: f64, y: f64) -> Point { + Point { x: x, y: y } + } +} + +struct Rectangle { + p1: Point, + p2: Point, +} + +impl Rectangle { + fn from(p1: Point, p2: Point) -> Self { + Self { p1, p2 } + } + + fn sum_x(self) -> f64 { + let p1 = self.p1; + let p2 = self.p2; + p1.x + p2.x + } +} + +fn main() { + let p1 = Point::origin(); + let p2 = Point::new(3.0, 4.0); + let rect = Rectangle::from(p1, p2); + + let sum = rect.sum_x(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + // multiple MethodCallExpr were causing issue #310 + let sum = rect.sum_x(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/mod-nameresolve.rs b/gcc/testsuite/rust/compile/torture/mod-nameresolve.rs new file mode 100644 index 00000000000..09a722681b0 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/mod-nameresolve.rs @@ -0,0 +1,5 @@ +mod foo { + struct A; // { dg-warning "struct is never constructed" } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/torture/mod1.rs b/gcc/testsuite/rust/compile/torture/mod1.rs new file mode 100644 index 00000000000..651678c6a34 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/mod1.rs @@ -0,0 +1,11 @@ +// This is testing name resolution + +mod _foo { + struct _A; +} + +mod _bar { + mod _barbis { + struct _B; + } +} diff --git a/gcc/testsuite/rust/compile/torture/mod2.rs b/gcc/testsuite/rust/compile/torture/mod2.rs new file mode 100644 index 00000000000..04722a94bb1 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/mod2.rs @@ -0,0 +1,13 @@ +mod foomod { + pub struct Foo {} +} + +impl foomod::Foo { + pub fn new() -> Self { + foomod::Foo {} + } +} + +fn main() { + let _a = foomod::Foo::new(); +} diff --git a/gcc/testsuite/rust/compile/torture/mod3.rs b/gcc/testsuite/rust/compile/torture/mod3.rs new file mode 100644 index 00000000000..2ace8c064d8 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/mod3.rs @@ -0,0 +1,22 @@ +// { dg-additional-options "-w" } +mod A { + pub mod B { + pub mod C { + pub struct Foo { + pub f: i32, + } + impl Foo { + pub fn new() -> Self { + Foo { f: 23i32 } + } + } + } + } +} + +fn main() -> i32 { + let a = A::B::C::Foo::new(); + let b = A::B::C::Foo { f: -23i32 }; + + a.f - b.f +} diff --git a/gcc/testsuite/rust/compile/torture/modules/mod.rs b/gcc/testsuite/rust/compile/torture/modules/mod.rs new file mode 100644 index 00000000000..3d65176b6c3 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/modules/mod.rs @@ -0,0 +1,3 @@ +pub fn return_12() -> i32 { + 12 +} diff --git a/gcc/testsuite/rust/compile/torture/modules/valid_path.rs b/gcc/testsuite/rust/compile/torture/modules/valid_path.rs new file mode 100644 index 00000000000..6a1519c3fc4 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/modules/valid_path.rs @@ -0,0 +1 @@ +fn unused() {} diff --git a/gcc/testsuite/rust/compile/torture/must_use1.rs b/gcc/testsuite/rust/compile/torture/must_use1.rs new file mode 100644 index 00000000000..95a6657c8c1 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/must_use1.rs @@ -0,0 +1,16 @@ +#[must_use = "TEST 1"] +fn test1() -> i32 { + 123 +} + +#[must_use = "TEST 2"] +fn test2() -> i32 { + 456 +} + +fn main() { + let _a = test1(); + + test2(); + // { dg-warning "ignoring return value of" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/must_use2.rs b/gcc/testsuite/rust/compile/torture/must_use2.rs new file mode 100644 index 00000000000..466f7ee7a14 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/must_use2.rs @@ -0,0 +1,16 @@ +trait A { + #[must_use] + fn test() -> i32; +} + +struct S; +impl A for S { + fn test() -> i32 { + 123 + } +} + +fn main() { + S::test(); + // { dg-warning "ignoring return value of" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/name_resolve1.rs b/gcc/testsuite/rust/compile/torture/name_resolve1.rs new file mode 100644 index 00000000000..817f48b60ee --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/name_resolve1.rs @@ -0,0 +1,23 @@ +struct Foo(i32, bool); + +impl Foo { + fn new(a: i32, b: bool) -> Foo { + Foo(a, b) + } + + fn test() -> i32 { + test() + } +} + +fn test() -> i32 { + 123 +} + +fn main() { + let a; + a = Foo::new(1, true); + + let b; + b = Foo::test(); +} diff --git a/gcc/testsuite/rust/compile/torture/negation_function.rs b/gcc/testsuite/rust/compile/torture/negation_function.rs new file mode 100644 index 00000000000..b592f9c00ef --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/negation_function.rs @@ -0,0 +1,7 @@ +fn ret1() -> i32 { + return 1; +} + +fn main() { + let _a = -ret1(); +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/nested_fn1.rs b/gcc/testsuite/rust/compile/torture/nested_fn1.rs new file mode 100644 index 00000000000..075b5dba8e0 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/nested_fn1.rs @@ -0,0 +1,10 @@ +pub fn main() { + let a = 123; + + fn test(x: i32) -> i32 { + x + 456 + } + + let b; + b = test(a); +} diff --git a/gcc/testsuite/rust/compile/torture/nested_fn2.rs b/gcc/testsuite/rust/compile/torture/nested_fn2.rs new file mode 100644 index 00000000000..7040c862e75 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/nested_fn2.rs @@ -0,0 +1,11 @@ +pub fn main() { + fn test(x: T) -> T { + x + } + + let mut a = 123; + a = test(a); + + let mut b = 456f32; + b = test(b); +} diff --git a/gcc/testsuite/rust/compile/torture/nested_struct1.rs b/gcc/testsuite/rust/compile/torture/nested_struct1.rs new file mode 100644 index 00000000000..2bd5eadd4c4 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/nested_struct1.rs @@ -0,0 +1,20 @@ +struct Point { + x: f64, + y: f64, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +struct Rectangle { + p1: Point, + p2: Point, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn main() { + let p1 = Point { x: 0.0, y: 0.0 }; + let p2 = Point { x: 2.0, y: 4.0 }; + let rect = Rectangle { p1, p2 }; + + let a = rect.p1.x; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/never_type1.rs b/gcc/testsuite/rust/compile/torture/never_type1.rs new file mode 100644 index 00000000000..0f15029097d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/never_type1.rs @@ -0,0 +1,22 @@ +fn foo() -> i32 { + let c; + let d; + + c = if false { + return 1; + } else { + 0.0 + }; + + d = if true { + 0.0 + } else { + return 1; + }; + + 0 +} + +fn main() { + foo(); +} diff --git a/gcc/testsuite/rust/compile/torture/not_shebang.rs b/gcc/testsuite/rust/compile/torture/not_shebang.rs new file mode 100644 index 00000000000..37e01b65940 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/not_shebang.rs @@ -0,0 +1,3 @@ +#! +[allow(unused)] +fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/not_shebang_block_comment.rs b/gcc/testsuite/rust/compile/torture/not_shebang_block_comment.rs new file mode 100644 index 00000000000..662f6506749 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/not_shebang_block_comment.rs @@ -0,0 +1 @@ +#!/*/this/is/a/comment*/[allow(unused)] fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/not_shebang_comment.rs b/gcc/testsuite/rust/compile/torture/not_shebang_comment.rs new file mode 100644 index 00000000000..273ae4e8e2a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/not_shebang_comment.rs @@ -0,0 +1,3 @@ +#!//this/is/a/comment +[allow(unused)] +fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/not_shebang_multiline_comment.rs b/gcc/testsuite/rust/compile/torture/not_shebang_multiline_comment.rs new file mode 100644 index 00000000000..86800b14cb3 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/not_shebang_multiline_comment.rs @@ -0,0 +1,7 @@ +#!//this/is/a/comment + +/* Also a /* nested */ + multiline // comment + with some more whitespace after, but then finally a [, so not a real #! line. */ + +[allow(unused)] fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/not_shebang_spaces.rs b/gcc/testsuite/rust/compile/torture/not_shebang_spaces.rs new file mode 100644 index 00000000000..6b94a69111a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/not_shebang_spaces.rs @@ -0,0 +1,6 @@ +#! + + [allow(unused)] + + fn main () { } + diff --git a/gcc/testsuite/rust/compile/torture/parameter_usage1.rs b/gcc/testsuite/rust/compile/torture/parameter_usage1.rs new file mode 100644 index 00000000000..448e9603a94 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/parameter_usage1.rs @@ -0,0 +1,8 @@ +fn test(a: i32, b: i32) -> i32 { + a + b +} + +fn main() { + let a = test(1, 4); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/parens1.rs b/gcc/testsuite/rust/compile/torture/parens1.rs new file mode 100644 index 00000000000..795eb960805 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/parens1.rs @@ -0,0 +1,5 @@ +fn main() { + let a = 123; + let b = a + (a * 2); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/pointer1.rs b/gcc/testsuite/rust/compile/torture/pointer1.rs new file mode 100644 index 00000000000..f283411abe2 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/pointer1.rs @@ -0,0 +1,9 @@ +pub fn main() { + let mut num = 2; + let r1: *const i32 = # + let r2 = unsafe { *r1 } + unsafe { *r1 }; + let r3 = num; + num = 4; + let r4 = num + unsafe { *r1 } * r3; + let _eightteen = r2 + r3 + r4; +} diff --git a/gcc/testsuite/rust/compile/torture/primconsts.rs b/gcc/testsuite/rust/compile/torture/primconsts.rs new file mode 100644 index 00000000000..bcf9456d059 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/primconsts.rs @@ -0,0 +1,72 @@ +const TRUE: bool = true; +const FALSE: bool = !TRUE; + +const U8ZERO: u8 = 0; +const U8ONE: u8 = U8ZERO + 1; +const U16ZERO: u16 = 0; +const U16ONE: u16 = U16ZERO + 1; +const U32ZERO: u32 = 0; +const U32ONE: u32 = U32ZERO + 1; +const U64ZERO: u64 = 0; +const U64ONE: u64 = U64ZERO + 1; +const U128ZERO: u128 = 0; +const U128ONE: u128 = U128ZERO + 1; + +const I8ZERO: i8 = 0; +const I8ONE: i8 = I8ZERO + 1; +const I16ZERO: i16 = 0; +const I16ONE: i16 = I16ZERO + 1; +const I32ZERO: i32 = 0; +const I32ONE: i32 = I32ZERO + 1; +const I64ZERO: i64 = 0; +const I64ONE: i64 = I64ZERO + 1; +const I128ZERO: i128 = 0; +const I128ONE: i128 = I128ZERO + 1; + +const F32ZERO: f32 = 0.0; +const F32ONE: f32 = F32ZERO + 1.0; +const F64ZERO: f64 = 0.0; +const F64ONE: f64 = F64ZERO + 1.0; + +const USIZEZERO: usize = 0; +const USIZEONE: usize = USIZEZERO + 1; +const ISIZEZERO: isize = 0; +const ISIZEONE: isize = ISIZEZERO + 1; + +/* Not yet supported +const CHARPI: char = '\u{03C0}'; +const STRHELLO: &str = "Hello World!"; +*/ + +extern "C" { fn abort (); } + +pub fn main () +{ + if TRUE == FALSE { unsafe { abort (); } } + if U8ZERO > U8ONE { unsafe { abort (); } } + if U16ZERO > U16ONE { unsafe { abort (); } } + if U32ZERO > U32ONE { unsafe { abort (); } } + if U64ZERO > U64ONE { unsafe { abort (); } } + if U128ZERO > U128ONE { unsafe { abort (); } } + + if I8ONE <= I8ZERO { unsafe { abort (); } } + if I16ONE <= I16ZERO { unsafe { abort (); } } + if I32ONE <= I32ZERO { unsafe { abort (); } } + if I64ONE <= I64ZERO { unsafe { abort (); } } + if I128ONE <= I128ZERO { unsafe { abort (); } } + + if F32ZERO + F32ONE != F32ONE { unsafe { abort (); } } + if F64ZERO + F64ONE != F64ONE { unsafe { abort (); } } + + if USIZEZERO + USIZEONE - USIZEONE + USIZEZERO != USIZEZERO + { + unsafe { abort (); } + } + if ISIZEZERO + ISIZEONE - ISIZEONE + ISIZEZERO != ISIZEZERO + { + unsafe { abort (); } + } + + // if CHARPI != '\u{03c0}' { unsafe { abort (); } } + // if STRHELLO != "Hello World!" { unsafe { abort (); } } +} diff --git a/gcc/testsuite/rust/compile/torture/prims_struct_eq.rs b/gcc/testsuite/rust/compile/torture/prims_struct_eq.rs new file mode 100644 index 00000000000..81ab7424627 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/prims_struct_eq.rs @@ -0,0 +1,91 @@ +extern "C" +{ + fn abort (); +} + +struct Prims +{ + b1: bool, + b2: bool, + b3: bool, + b4: bool, + c1: char, + c2: char, + u81: u8, + u82: u8, + u83: u8, + u84: u8, + i81: i8, + i82: i8, + i83: i8, + i84: i8, + u161: u16, + u162: u16, + i161: i16, + i162: i16, + u321: u32, + u322: u32, + i321: i32, + i322: i32, + u641: u64, + i641: i64, + u1281: u128, + i1281: i128, + usize1: usize, + isize1: isize, +} + +fn prims_eq (p1: Prims, p2: Prims) -> bool +{ + return p1.b1 == p2.b1 + && p1.b2 == p2.b2 + && p1.b3 == p2.b3 + && p1.b4 == p2.b4 + && p1.c1 == p2.c1 + && p1.c2 == p2.c2 + && p1.u81 == p2.u81 + && p1.u82 == p2.u82 + && p1.u83 == p2.u83 + && p1.u84 == p2.u84 + && p1.i81 == p2.i81 + && p1.i82 == p2.i82 + && p1.i83 == p2.i83 + && p1.i84 == p2.i84 + && p1.u161 == p2.u161 + && p1.u162 == p2.u162 + && p1.i161 == p2.i161 + && p1.i162 == p2.i162 + && p1.u321 == p2.u321 + && p1.u322 == p2.u322 + && p1.i321 == p2.i321 + && p1.i322 == p2.i322 + && p1.u641 == p2.u641 + && p1.i641 == p2.i641 + && p1.u1281 == p2.u1281 + && p1.i1281 == p2.i1281 + && p1.usize1 == p2.usize1 + && p1.isize1 == p2.isize1; +} + +pub fn main () +{ + let p1 = Prims { b1: true, b2: false, b3: false, b4: true, + c1: 'a', c2: 'b', + u81: 1, u82: 2, u83: 3, u84: 4, + i81: -1, i82: -2, i83: -3, i84: -4, + u161: 1, u162: 2, + i161: -1, i162: -2, + u321: 1, u322: 2, + i321: -1, i322: -2, + u641: 1, + i641: -1, + u1281: 1, + i1281: -1, + usize1: 1, + isize1: -1 }; + let p2 = Prims { usize1: 1, .. p1 }; + let p3 = Prims { u1281: 0, .. p2 }; + let p4 = Prims { i1281: 0, .. p3 }; + if !prims_eq (p1, p2) { unsafe { abort (); } } + if prims_eq (p3, p4) { unsafe { abort (); } } +} diff --git a/gcc/testsuite/rust/compile/torture/range-lang-item1.rs b/gcc/testsuite/rust/compile/torture/range-lang-item1.rs new file mode 100644 index 00000000000..86946162276 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/range-lang-item1.rs @@ -0,0 +1,32 @@ +// { dg-additional-options "-w" } +#[lang = "RangeFull"] +pub struct RangeFull; + +#[lang = "Range"] +pub struct Range { + pub start: Idx, + pub end: Idx, +} + +#[lang = "RangeFrom"] +pub struct RangeFrom { + pub start: Idx, +} + +#[lang = "RangeTo"] +pub struct RangeTo { + pub end: Idx, +} + +#[lang = "RangeInclusive"] +pub struct RangeInclusive { + pub start: Idx, + pub end: Idx, +} + +fn test() { + let a = 1..2; // range + let b = 1..; // range from + let c = ..3; // range to + let d = 0..=2; // range inclusive +} diff --git a/gcc/testsuite/rust/compile/torture/raw_identifiers.rs b/gcc/testsuite/rust/compile/torture/raw_identifiers.rs new file mode 100644 index 00000000000..8746f337048 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/raw_identifiers.rs @@ -0,0 +1,3 @@ +pub fn square(num: i32) -> i32 { /* { dg-warning "used" } */ + r#num * num +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/raw_identifiers_keywords.rs b/gcc/testsuite/rust/compile/torture/raw_identifiers_keywords.rs new file mode 100644 index 00000000000..c9aa3cf4938 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/raw_identifiers_keywords.rs @@ -0,0 +1,3 @@ +pub fn plus(r#break: i32, r#unsafe: i32) -> i32 { /* { dg-warning "used" } */ + r#break + r#unsafe +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/recursive_fn1.rs b/gcc/testsuite/rust/compile/torture/recursive_fn1.rs new file mode 100644 index 00000000000..e13b41f70bd --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/recursive_fn1.rs @@ -0,0 +1,12 @@ +fn gcd(x: i32, y: i32) -> i32 { + if y == 0 { + x + } else { + gcd(y, x % y) + } +} + +fn main() { + let a = gcd(100, 5); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/return_function.rs b/gcc/testsuite/rust/compile/torture/return_function.rs new file mode 100644 index 00000000000..084adaf7f24 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/return_function.rs @@ -0,0 +1,5 @@ +fn foo() {} + +fn main() { + return foo(); +} diff --git a/gcc/testsuite/rust/compile/torture/scoping1.rs b/gcc/testsuite/rust/compile/torture/scoping1.rs new file mode 100644 index 00000000000..8bc8ede5f7c --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/scoping1.rs @@ -0,0 +1,11 @@ +fn main() { + let x = 1; + { + let mut x = true; + { + x = false; + } + } + let x = x + 1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/self_type1.rs b/gcc/testsuite/rust/compile/torture/self_type1.rs new file mode 100644 index 00000000000..373d6dd5a60 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/self_type1.rs @@ -0,0 +1,12 @@ +struct Foo(i32, bool); + +impl Foo { + fn new(a: i32, b: bool) -> Self { + Self(a, b) + } +} + +fn main() { + let a; + a = Foo::new(1, true); +} diff --git a/gcc/testsuite/rust/compile/torture/shadow1.rs b/gcc/testsuite/rust/compile/torture/shadow1.rs new file mode 100644 index 00000000000..b60e7936de9 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/shadow1.rs @@ -0,0 +1,6 @@ +fn main() { + let mut x = 5; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let mut x; + x = true; +} diff --git a/gcc/testsuite/rust/compile/torture/shadow2.rs b/gcc/testsuite/rust/compile/torture/shadow2.rs new file mode 100644 index 00000000000..161dc380a07 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/shadow2.rs @@ -0,0 +1,5 @@ +fn main() { + let x = 1; + let x = x + 1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/shebang.rs b/gcc/testsuite/rust/compile/torture/shebang.rs new file mode 100755 index 00000000000..1c8b9c9a955 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/shebang.rs @@ -0,0 +1,3 @@ +#!/usr/bin/env cat + +fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/shebang_plus_attr.rs b/gcc/testsuite/rust/compile/torture/shebang_plus_attr.rs new file mode 100755 index 00000000000..075bc6cf594 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/shebang_plus_attr.rs @@ -0,0 +1,3 @@ +#!/usr/bin/env cat +#![allow(unused)] +fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/shebang_plus_attr2.rs b/gcc/testsuite/rust/compile/torture/shebang_plus_attr2.rs new file mode 100755 index 00000000000..ece8a52381c --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/shebang_plus_attr2.rs @@ -0,0 +1,3 @@ +#!//usr/bin/env cat +#![allow(unused)] +fn main () { } diff --git a/gcc/testsuite/rust/compile/torture/static_function.rs b/gcc/testsuite/rust/compile/torture/static_function.rs new file mode 100644 index 00000000000..8e3a3795023 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/static_function.rs @@ -0,0 +1,8 @@ +fn test(x: i32) -> i32 { + return x + 1; +} + +fn main() { + let call_test = test(1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/static_var1.rs b/gcc/testsuite/rust/compile/torture/static_var1.rs new file mode 100644 index 00000000000..5be0e75ce72 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/static_var1.rs @@ -0,0 +1,6 @@ +static x:i32 = 3; + +fn main() { + let y = x +1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/stmt_with_block1.rs b/gcc/testsuite/rust/compile/torture/stmt_with_block1.rs new file mode 100644 index 00000000000..b6aa56cc2e6 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/stmt_with_block1.rs @@ -0,0 +1,13 @@ +fn test(x: i32) -> i32 { + if x > 1 { 1 } else { 2 }; + if x > 1 { 1; } else { 2; } + + { 3; } + { 3 }; + + { 3 } +} + +fn main() { + let a = test(0); // { dg-warning "unused name" } +} diff --git a/gcc/testsuite/rust/compile/torture/str1.rs b/gcc/testsuite/rust/compile/torture/str1.rs new file mode 100644 index 00000000000..088827853d8 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/str1.rs @@ -0,0 +1,7 @@ +fn main() { + let a; + a = "hello world infer"; + + let b: &str; + b = "hello world specified"; +} diff --git a/gcc/testsuite/rust/compile/torture/struct_access1.rs b/gcc/testsuite/rust/compile/torture/struct_access1.rs new file mode 100644 index 00000000000..ec85d289fb5 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_access1.rs @@ -0,0 +1,12 @@ +struct Foo { + one: i32, + two: i32, +} + +fn main() { + let struct_test = Foo { one: 1, two: 2 }; + let a = struct_test.one; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = struct_test.two; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/struct_base_init_1.rs b/gcc/testsuite/rust/compile/torture/struct_base_init_1.rs new file mode 100644 index 00000000000..ee00c2c468b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_base_init_1.rs @@ -0,0 +1,13 @@ +struct Foo { + a: i32, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } + b: i32, +} + +fn foo() -> Foo { + Foo { a: 42, b: 32 } +} + +fn main() { + let _f = Foo { a: 10, ..foo() }; +} diff --git a/gcc/testsuite/rust/compile/torture/struct_decl.rs b/gcc/testsuite/rust/compile/torture/struct_decl.rs new file mode 100644 index 00000000000..9e8ea6b100b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_decl.rs @@ -0,0 +1,14 @@ +// { dg-additional-options "-fdump-tree-gimple -frust-crate=example" } + +struct Foo { + a: u16, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + b: u8, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn main() { + let my_foo = Foo { a: 1, b: 2 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + // { dg-final { scan-tree-dump-times {(?n)const struct example::Foo my_foo;$} 1 gimple } } +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init.rs b/gcc/testsuite/rust/compile/torture/struct_init.rs new file mode 100644 index 00000000000..1926f73b21d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init.rs @@ -0,0 +1,11 @@ +struct Foo { + one: i32, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } + two: i32, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn main() { + let struct_test = Foo { one: 1, two: 2 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init_10.rs b/gcc/testsuite/rust/compile/torture/struct_init_10.rs new file mode 100644 index 00000000000..7fbceb03974 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init_10.rs @@ -0,0 +1,9 @@ +fn main() { + struct foo { + a: i32, + b: f32, + }; + + let a; + a = foo { a: 123, b: 456f32 }; +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init_11.rs b/gcc/testsuite/rust/compile/torture/struct_init_11.rs new file mode 100644 index 00000000000..16a2f072566 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init_11.rs @@ -0,0 +1,34 @@ +pub fn main() { + struct O(i32); + struct T(i32, i32); + struct M(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32); + + // tuples + let z = (); + let o = (0,); + let f = o.0; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let t = (0, 1); + let s = t.1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let m = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + let l = m.10; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + // tuple structs + let so = O(0); + let sf = so.0; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let st = T(0, 1); + let fs = st.1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let sm = M(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + let sl = sm.10; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + z +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init_2.rs b/gcc/testsuite/rust/compile/torture/struct_init_2.rs new file mode 100644 index 00000000000..d7040d3d96d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init_2.rs @@ -0,0 +1,6 @@ +struct Foo(f32, f32); + +fn main() { + let a = Foo { 0: 10.0, 1: 20.0 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init_3.rs b/gcc/testsuite/rust/compile/torture/struct_init_3.rs new file mode 100644 index 00000000000..1398f8e7b86 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init_3.rs @@ -0,0 +1,13 @@ +struct Foo { + a: i32, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } + b: i32, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn main() { + let a = 1; + let b = 2; + let c = Foo { a, b }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init_4.rs b/gcc/testsuite/rust/compile/torture/struct_init_4.rs new file mode 100644 index 00000000000..2b2746aba7a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init_4.rs @@ -0,0 +1,13 @@ +struct Foo { + a: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + b: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn main() { + let a = Foo { a: 1, b: 2 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = Foo { a: 3, b: 4, ..a }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init_5.rs b/gcc/testsuite/rust/compile/torture/struct_init_5.rs new file mode 100644 index 00000000000..891f64540fe --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init_5.rs @@ -0,0 +1,10 @@ +struct Foo { + a: i32, + b: i32, +} + +fn main() { + let a = Foo { a: 1, b: 2 }; + let b = Foo { ..a }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init_6.rs b/gcc/testsuite/rust/compile/torture/struct_init_6.rs new file mode 100644 index 00000000000..9fc52ed5c50 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init_6.rs @@ -0,0 +1,11 @@ +struct Foo { + a: i32, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } + b: i32, +} + +fn main() { + let a = Foo { a: 1, b: 2 }; + let b = Foo { a: 1, ..a }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init_7.rs b/gcc/testsuite/rust/compile/torture/struct_init_7.rs new file mode 100644 index 00000000000..36dc00aca60 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init_7.rs @@ -0,0 +1,11 @@ +struct Foo { + a: i32, + b: f32, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn main() { + let c = Foo { a: 1, b: 2f32 }; + let b = Foo { b: 4f32, ..c }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init_8.rs b/gcc/testsuite/rust/compile/torture/struct_init_8.rs new file mode 100644 index 00000000000..411ff7d1c6f --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init_8.rs @@ -0,0 +1,7 @@ +struct Foo(f32, i32); + +fn main() { + let a = Foo { 1: 1, 0: 2f32 }; + let b = Foo { ..a }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/struct_init_9.rs b/gcc/testsuite/rust/compile/torture/struct_init_9.rs new file mode 100644 index 00000000000..2daa078d5b3 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/struct_init_9.rs @@ -0,0 +1,6 @@ +fn main() { + struct foo(i32, f32); + + let a; + a = foo(123, 456f32); +} diff --git a/gcc/testsuite/rust/compile/torture/top_attr.rs b/gcc/testsuite/rust/compile/torture/top_attr.rs new file mode 100644 index 00000000000..0671369cb12 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/top_attr.rs @@ -0,0 +1,5 @@ +#![crate_name = "name"] + + +#[allow(dead_code)] +fn main() {} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/traits1.rs b/gcc/testsuite/rust/compile/torture/traits1.rs new file mode 100644 index 00000000000..90357738a81 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits1.rs @@ -0,0 +1,16 @@ +trait Foo { + fn bar() -> i32; +} + +struct Test(i32, f32); + +impl Foo for Test { + fn bar() -> i32 { + 123 + } +} + +fn main() { + let a: i32; + a = Test::bar(); +} diff --git a/gcc/testsuite/rust/compile/torture/traits10.rs b/gcc/testsuite/rust/compile/torture/traits10.rs new file mode 100644 index 00000000000..a02927007b3 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits10.rs @@ -0,0 +1,30 @@ +trait Foo // where +// Self: Sized, +{ + fn get(self) -> i32; + + fn test(self) -> i32 { + self.get() + } +} + +struct Bar(i32); +impl Foo for Bar { + fn get(self) -> i32 { + self.0 + } +} + +fn main() { + let a; + a = Bar(123); + + let b; + b = Bar::get(a); + + let a; + a = Bar(123); + + let b; + b = a.test(); +} diff --git a/gcc/testsuite/rust/compile/torture/traits11.rs b/gcc/testsuite/rust/compile/torture/traits11.rs new file mode 100644 index 00000000000..41c82f01b6d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits11.rs @@ -0,0 +1,31 @@ +trait Foo { + type A; + + fn test(a: Self::A) -> Self::A { + a + } +} + +struct Bar(i32); +impl Foo for Bar { + type A = i32; +} + +struct Baz(f32); +impl Foo for Baz { + type A = f32; +} + +fn main() { + let a; + a = Bar(123); + + let b; + b = Bar::test(a.0); + + let c; + c = Baz(123f32); + + let d; + d = Baz::test(c.0); +} diff --git a/gcc/testsuite/rust/compile/torture/traits12.rs b/gcc/testsuite/rust/compile/torture/traits12.rs new file mode 100644 index 00000000000..a55b965baf0 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits12.rs @@ -0,0 +1,29 @@ +trait Foo { + type A; + + fn test(a: Self::A) -> Self::A { + a + } +} + +struct Bar(i32); +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl Foo for Bar { + type A = i32; +} + +struct Baz(f32); +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl Foo for Baz { + type A = f32; +} + +fn main() { + let a: ::A; + a = 123f32; + + let b; + b = ::test(a); +} diff --git a/gcc/testsuite/rust/compile/torture/traits13.rs b/gcc/testsuite/rust/compile/torture/traits13.rs new file mode 100644 index 00000000000..326f0390756 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits13.rs @@ -0,0 +1,17 @@ +trait Trait { + const FOO: usize; + type Target; +} + +struct S; +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl Trait for S { + const FOO: usize = 0; + type Target = usize; +} + +fn main() { + let a: ::Target; + a = ::FOO; +} diff --git a/gcc/testsuite/rust/compile/torture/traits14.rs b/gcc/testsuite/rust/compile/torture/traits14.rs new file mode 100644 index 00000000000..8bca0d5c1f6 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits14.rs @@ -0,0 +1,23 @@ +trait Foo { + type A; + + fn test(a: T) -> T { + a + } +} + +struct Bar(T); +impl Foo for Bar { + type A = T; +} + +pub fn main() { + let a; + a = Bar(123); + + let b: as Foo>::A; + b = 456; + + let c: as Foo>::A; + c = as Foo>::test(a.0); +} diff --git a/gcc/testsuite/rust/compile/torture/traits15.rs b/gcc/testsuite/rust/compile/torture/traits15.rs new file mode 100644 index 00000000000..c8c40b78b45 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits15.rs @@ -0,0 +1,23 @@ +trait Foo { + type A; + + fn test(a: T, b: Self::A) -> (T, Self::A) { + (a, b) + } +} + +struct Bar(T); +impl Foo for Bar { + type A = T; +} + +pub fn main() { + let a; + a = Bar(123); + + let b: as Foo>::A; + b = 456; + + let c; + c = as Foo>::test(a.0, 123); +} diff --git a/gcc/testsuite/rust/compile/torture/traits16.rs b/gcc/testsuite/rust/compile/torture/traits16.rs new file mode 100644 index 00000000000..afc4a86de6d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits16.rs @@ -0,0 +1,20 @@ +trait A { + fn a() -> i32 { + 123 + } + + fn b() -> i32 { + Self::a() + 456 + } +} + +struct S; +impl A for S {} + +fn main() { + let a; + a = S::a(); + + let b; + b = S::b(); +} diff --git a/gcc/testsuite/rust/compile/torture/traits17.rs b/gcc/testsuite/rust/compile/torture/traits17.rs new file mode 100644 index 00000000000..6da8bcb0082 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits17.rs @@ -0,0 +1,23 @@ +trait A { + fn a() -> i32 { + 123 + } +} + +trait B: A { + fn b() -> i32 { + Self::a() + 456 + } +} + +struct S; +impl A for S {} +impl B for S {} + +fn main() { + let a; + a = S::a(); + + let b; + b = S::b(); +} diff --git a/gcc/testsuite/rust/compile/torture/traits18.rs b/gcc/testsuite/rust/compile/torture/traits18.rs new file mode 100644 index 00000000000..63319dd2daa --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits18.rs @@ -0,0 +1,5 @@ +trait Foo<'a> {} + +trait Bar { + type Item: for<'a> Foo<'a>; +} diff --git a/gcc/testsuite/rust/compile/torture/traits19.rs b/gcc/testsuite/rust/compile/torture/traits19.rs new file mode 100644 index 00000000000..4412656f535 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits19.rs @@ -0,0 +1,33 @@ +// { dg-additional-options "-w" } +trait Get { + type Value; + fn get(&self) -> &::Value; +} + +struct Struct { + x: isize, +} + +impl Get for Struct { + type Value = isize; + fn get(&self) -> &isize { + &self.x + } +} + +trait Grab { + type U; + fn grab(&self) -> &::U; +} + +impl Grab for T { + type U = ::Value; + fn grab(&self) -> &::Value { + self.get() + } +} + +fn main() { + let s = Struct { x: 100 }; + let a = s.grab(); +} diff --git a/gcc/testsuite/rust/compile/torture/traits2.rs b/gcc/testsuite/rust/compile/torture/traits2.rs new file mode 100644 index 00000000000..fc6eb6002e0 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits2.rs @@ -0,0 +1,16 @@ +trait Foo { + fn bar() -> i32; +} + +struct Test(T); + +impl Foo for Test { + fn bar() -> i32 { + 123 + } +} + +fn main() { + let a: i32; + a = Test::::bar(); +} diff --git a/gcc/testsuite/rust/compile/torture/traits3.rs b/gcc/testsuite/rust/compile/torture/traits3.rs new file mode 100644 index 00000000000..deeb81e0946 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits3.rs @@ -0,0 +1,15 @@ +pub trait Foo { + fn Bar(self) -> i32; +} + +struct Baz; +// { dg-warning "struct is never constructed: .Baz." "" { target *-*-* } .-1 } + +impl Foo for Baz { + fn Bar(self) -> i32 { + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + 123 + } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/torture/traits4.rs b/gcc/testsuite/rust/compile/torture/traits4.rs new file mode 100644 index 00000000000..67b012c11f5 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits4.rs @@ -0,0 +1,21 @@ +trait Foo { + type A; + type B; + + fn new(a: Self::A, b: Self::B) -> Self; +} + +struct Baz(i32, f32); + +impl Foo for Baz { + type A = i32; + type B = f32; + + fn new(a: Self::A, b: Self::B) -> Self { + Baz(a, b) + } +} + +fn main() { + Baz::new(123, 456f32); +} diff --git a/gcc/testsuite/rust/compile/torture/traits5.rs b/gcc/testsuite/rust/compile/torture/traits5.rs new file mode 100644 index 00000000000..445b0658f5c --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits5.rs @@ -0,0 +1,21 @@ +trait Foo { + type A; + type B; + + fn new(a: Self::A, b: Self::B) -> Self; +} + +struct Baz(i32, f32); + +impl Foo for Baz { + type A = i32; + type B = f32; + + fn new(a: i32, b: f32) -> Self { + Baz(a, b) + } +} + +fn main() { + Baz::new(123, 456f32); +} diff --git a/gcc/testsuite/rust/compile/torture/traits6.rs b/gcc/testsuite/rust/compile/torture/traits6.rs new file mode 100644 index 00000000000..260dde3f465 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits6.rs @@ -0,0 +1,20 @@ +trait Foo { + type A; + + fn baz(a: Self::A) -> Self::A; +} + +struct Bar(T); + +impl Foo for Bar { + type A = T; + + fn baz(a: Self::A) -> T { + a + } +} + +fn main() { + let a; + a = Bar::::baz(123); +} diff --git a/gcc/testsuite/rust/compile/torture/traits7.rs b/gcc/testsuite/rust/compile/torture/traits7.rs new file mode 100644 index 00000000000..7bc3384ab41 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits7.rs @@ -0,0 +1,19 @@ +trait Foo { + const A: i32; + + fn test(self); +} + +struct Bar; +impl Foo for Bar { + const A: i32 = 123; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + fn test(self) {} + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +fn main() { + let a = Bar; + a.test(); +} diff --git a/gcc/testsuite/rust/compile/torture/traits8.rs b/gcc/testsuite/rust/compile/torture/traits8.rs new file mode 100644 index 00000000000..459032fb4a2 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits8.rs @@ -0,0 +1,21 @@ +trait Foo { + fn default() -> i32; +} + +struct Bar(i32); +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl Foo for Bar { + fn default() -> i32 { + 123 + } +} + +fn type_bound_test() -> i32 { + T::default() +} + +fn main() { + let a; + a = type_bound_test::(); +} diff --git a/gcc/testsuite/rust/compile/torture/traits9.rs b/gcc/testsuite/rust/compile/torture/traits9.rs new file mode 100644 index 00000000000..89e4bf19b0c --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits9.rs @@ -0,0 +1,27 @@ +trait Foo { + fn default() -> i32; + fn get(self) -> i32; +} + +struct Bar(i32); +impl Foo for Bar { + fn default() -> i32 { + 123 + } + + fn get(self) -> i32 { + self.0 + } +} + +fn type_bound_test(a: T) -> i32 { + T::default() + a.get() +} + +fn main() { + let a; + a = Bar(456); + + let b; + b = type_bound_test(a); +} diff --git a/gcc/testsuite/rust/compile/torture/transmute-size-check-1.rs b/gcc/testsuite/rust/compile/torture/transmute-size-check-1.rs new file mode 100644 index 00000000000..461a35de8ef --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/transmute-size-check-1.rs @@ -0,0 +1,11 @@ +mod mem { + extern "rust-intrinsic" { + fn size_of() -> usize; + fn transmute(_: U) -> V; // { dg-error "cannot transmute between types of different sizes, or dependently-sized types" } + } +} + +fn main() { + let a = 123; + let _b: [u32; mem::size_of::()] = unsafe { mem::transmute(a) }; +} diff --git a/gcc/testsuite/rust/compile/torture/transmute1.rs b/gcc/testsuite/rust/compile/torture/transmute1.rs new file mode 100644 index 00000000000..af9a55d1b97 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/transmute1.rs @@ -0,0 +1,11 @@ +mod mem { + extern "rust-intrinsic" { + fn size_of() -> usize; + fn transmute(_: U) -> V; + } +} + +fn main() { + let a = 123; + let _b: [u8; mem::size_of::()] = unsafe { mem::transmute(a) }; +} diff --git a/gcc/testsuite/rust/compile/torture/tuple1.rs b/gcc/testsuite/rust/compile/torture/tuple1.rs new file mode 100644 index 00000000000..9e6f613f682 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple1.rs @@ -0,0 +1,6 @@ +fn main() { + let a: (i32, bool) = (123, true); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b; + b = (456, 5f32); +} diff --git a/gcc/testsuite/rust/compile/torture/tuple2.rs b/gcc/testsuite/rust/compile/torture/tuple2.rs new file mode 100644 index 00000000000..ab3d0b8715b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple2.rs @@ -0,0 +1,5 @@ +fn main() { + let a = 123; + let b = (a,); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/tuple3.rs b/gcc/testsuite/rust/compile/torture/tuple3.rs new file mode 100644 index 00000000000..d0fb6fc4429 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple3.rs @@ -0,0 +1,9 @@ +fn main() { + let a = (1, true); + + let b; + let c; + + b = a.0; + c = a.1; +} diff --git a/gcc/testsuite/rust/compile/torture/tuple_enum_variants.rs b/gcc/testsuite/rust/compile/torture/tuple_enum_variants.rs new file mode 100644 index 00000000000..d953e3d89a1 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple_enum_variants.rs @@ -0,0 +1,23 @@ +enum E { + T0(), + T1(i32), + T2(i32, u32), +} + +/* The following doesn't parse yet... +fn f(e0: E, e1: E, e2: E) -> (E,E,E,()) +{ + let e = e0; + let f = e1; + let g = e2; + (e,f,g,()) +} + +fn main() +{ + let e0 = E::T0(); + let e1 = E::T1(0); + let e2 = E::T2(0,1); + f(e0, e1, e2).3 +} +*/ diff --git a/gcc/testsuite/rust/compile/torture/tuple_field_access.rs b/gcc/testsuite/rust/compile/torture/tuple_field_access.rs new file mode 100644 index 00000000000..8d1bbe9906c --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple_field_access.rs @@ -0,0 +1,6 @@ +struct Foo(i32, i32); + +fn main() { + let mut a = Foo(1, 2); + a.0 = 22; +} diff --git a/gcc/testsuite/rust/compile/torture/tuple_function.rs b/gcc/testsuite/rust/compile/torture/tuple_function.rs new file mode 100644 index 00000000000..514b586cc09 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple_function.rs @@ -0,0 +1,6 @@ +fn foo() -> i32 { + return 1; +} +fn main() { + let _a = (foo(), 2); +} diff --git a/gcc/testsuite/rust/compile/torture/tuple_index.rs b/gcc/testsuite/rust/compile/torture/tuple_index.rs new file mode 100644 index 00000000000..f904fae9b5b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple_index.rs @@ -0,0 +1,32 @@ +fn main() +{ + // tuples + let z = (); + + let o = (0,); + let _f = o.0; + + let t = (0,1); + let _s = t.1; + + let m = (0,1,2,3,4,5,6,7,8,9,10); + let _l = m.10; + + // tuple structs + struct E(); + let _e = E(); + + struct O(i32); + let so = O(0); + let _sf = so.0; + + struct T(i32,i32); + let st = T(0,1); + let _fs = st.1; + + struct M(i32,i32,i32,i32,i32,i32,i32,i32,i32,i32,i32); + let sm = M(0,1,2,3,4,5,6,7,8,9,10); + let _sl = sm.10; + + z +} diff --git a/gcc/testsuite/rust/compile/torture/tuple_struct1.rs b/gcc/testsuite/rust/compile/torture/tuple_struct1.rs new file mode 100644 index 00000000000..0ac19b179a9 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple_struct1.rs @@ -0,0 +1,6 @@ +struct Foo(i32, i32, bool); + +fn main() { + let a = Foo(1, 2, true); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/tuple_struct2.rs b/gcc/testsuite/rust/compile/torture/tuple_struct2.rs new file mode 100644 index 00000000000..5e0a76e1de8 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple_struct2.rs @@ -0,0 +1,11 @@ +struct Foo(i32, bool); + +fn main() { + let a = Foo(1, true); + + let b; + let c; + + b = a.0; + c = a.1; +} diff --git a/gcc/testsuite/rust/compile/torture/tuple_struct_unit.rs b/gcc/testsuite/rust/compile/torture/tuple_struct_unit.rs new file mode 100644 index 00000000000..cda19d2af0b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple_struct_unit.rs @@ -0,0 +1,11 @@ +struct E(); +struct T(E,E,()); + +fn main() +{ + let z0 = E(); + let z1 = E(); + let t = T(z0,z1,()); + let z = t.2; + z +} diff --git a/gcc/testsuite/rust/compile/torture/tuple_struct_unused.rs b/gcc/testsuite/rust/compile/torture/tuple_struct_unused.rs new file mode 100644 index 00000000000..8da0a50632b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/tuple_struct_unused.rs @@ -0,0 +1,4 @@ +struct Foo(i32, i32); +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +fn main() {} diff --git a/gcc/testsuite/rust/compile/torture/type-alias1.rs b/gcc/testsuite/rust/compile/torture/type-alias1.rs new file mode 100644 index 00000000000..78bf0461036 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/type-alias1.rs @@ -0,0 +1,6 @@ +type TypeAlias = (i32, u32); + +fn main() { + let a: TypeAlias; + a = (123, 456); +} diff --git a/gcc/testsuite/rust/compile/torture/type-alias2.rs b/gcc/testsuite/rust/compile/torture/type-alias2.rs new file mode 100644 index 00000000000..a3e3f4e6851 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/type-alias2.rs @@ -0,0 +1,8 @@ +type x = u32; + +fn main() { + let x: x = 1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let y: x = 2; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/type_infer1.rs b/gcc/testsuite/rust/compile/torture/type_infer1.rs new file mode 100644 index 00000000000..3fee7282bde --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/type_infer1.rs @@ -0,0 +1,24 @@ +struct Foo { + one: i32, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } + two: i32, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn test(x: i32) -> i32 { + return x + 1; +} + +fn main() { + let logical: bool = true; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let an_integer = 5; + let mut default_integer = 7; + + default_integer = 1 + an_integer; + + let call_test = test(1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let struct_test = Foo { one: 1, two: 2 }; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/type_infer2.rs b/gcc/testsuite/rust/compile/torture/type_infer2.rs new file mode 100644 index 00000000000..dcddda42729 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/type_infer2.rs @@ -0,0 +1,9 @@ +fn test(x: i32) -> i32 { + return x + 1; +} + +fn main() { + let an_integer = 5; + let call_test = test(an_integer + 1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/type_infer3.rs b/gcc/testsuite/rust/compile/torture/type_infer3.rs new file mode 100644 index 00000000000..303dd3d1f18 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/type_infer3.rs @@ -0,0 +1,14 @@ +fn test(x: i32) -> i32 { + return x + 1; +} + +fn main() { + let mut an_integer = 5; + an_integer = test(1) + 3; + + let mut x; + x = 1; + + let call_test = test(1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/type_infer4.rs b/gcc/testsuite/rust/compile/torture/type_infer4.rs new file mode 100644 index 00000000000..77a919f262a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/type_infer4.rs @@ -0,0 +1,11 @@ +fn main() { + let xs: [i32; 5] = [1, 2, 3, 4, 5]; + let xy = [6, 7, 8]; + + let a = xs[0]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = xy[2]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let mut c; + c = xs[0]; +} diff --git a/gcc/testsuite/rust/compile/torture/type_infer5.rs b/gcc/testsuite/rust/compile/torture/type_infer5.rs new file mode 100644 index 00000000000..2c2602a161f --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/type_infer5.rs @@ -0,0 +1,13 @@ +struct Foo { + a: i32, + b: i32, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn main() { + let a; + a = Foo { a: 1, b: 2 }; + + let b = a.a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/type_infer6.rs b/gcc/testsuite/rust/compile/torture/type_infer6.rs new file mode 100644 index 00000000000..6f5863f0107 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/type_infer6.rs @@ -0,0 +1,14 @@ +fn test(x: u32) -> u32 { + return x + 1; +} + +fn main() { + let a; + a = 1; + let b = test(a); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let c = 1; + let d = test(c + 1); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/unary_operators.rs b/gcc/testsuite/rust/compile/torture/unary_operators.rs new file mode 100644 index 00000000000..9be729c04e3 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unary_operators.rs @@ -0,0 +1,8 @@ +// { dg-prune-output "warning: unused name" } as there are many of these expected. + +fn main() { + let a: i32 = -1; + let b: i32 = 3 - -1; + let c: bool = !false; + let d: i32 = !3; +} diff --git a/gcc/testsuite/rust/compile/torture/undended-string-1.rs b/gcc/testsuite/rust/compile/torture/undended-string-1.rs new file mode 100644 index 00000000000..66f0cd52269 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/undended-string-1.rs @@ -0,0 +1,5 @@ +// { dg-excess-errors "...." } +fn main() { + // { dg-error "unended string literal" "" { target *-*-* } .+1 } + let s = "123 +} diff --git a/gcc/testsuite/rust/compile/torture/undended-string-2.rs b/gcc/testsuite/rust/compile/torture/undended-string-2.rs new file mode 100644 index 00000000000..c0f424927c2 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/undended-string-2.rs @@ -0,0 +1,5 @@ +// { dg-excess-errors "...." } +fn main() { + // { dg-error "unended byte string literal" "" { target *-*-* } .+1 } + let s = b"123 +} diff --git a/gcc/testsuite/rust/compile/torture/underscore_id.rs b/gcc/testsuite/rust/compile/torture/underscore_id.rs new file mode 100644 index 00000000000..2c106c55df9 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/underscore_id.rs @@ -0,0 +1,4 @@ +fn main() { + let _unused_but_fine = 12; + let unused = 12; // { dg-warning "unused name" } +} diff --git a/gcc/testsuite/rust/compile/torture/union.rs b/gcc/testsuite/rust/compile/torture/union.rs new file mode 100644 index 00000000000..724168817ad --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/union.rs @@ -0,0 +1,32 @@ +union U +{ + f1: u8 +} + +union V +{ + f1: u8, + f2: u16, + f3: i32, +} + +struct S +{ + f1: U, + f2: V +} + +fn main () +{ + let u = U { f1: 16 }; + let v = V { f2: 365 }; + let s = S { f1: u, f2: v }; + let _v125 = unsafe + { let mut uv: u64; + uv = s.f1.f1 as u64; + uv += s.f2.f1 as u64; + uv += s.f2.f2 as u64; + uv -= s.f2.f3 as u64; + uv + }; +} diff --git a/gcc/testsuite/rust/compile/torture/union_union.rs b/gcc/testsuite/rust/compile/torture/union_union.rs new file mode 100644 index 00000000000..9feb145a692 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/union_union.rs @@ -0,0 +1,27 @@ +union union +{ + union: u32, + inion: i32, + u8ion: u8, + i64on: i64, + u64on: u64 +} + +pub fn main () +{ + let union = union { union: 2 }; + let inion = union { inion: -2 }; + let mut mnion = union { inion: -16 }; + let m1 = unsafe { mnion.union }; + unsafe { mnion.union = union.union }; + let m2 = unsafe { mnion.inion }; + let u1 = unsafe { union.union }; + let i1 = unsafe { union.inion }; + let u2 = unsafe { inion.union }; + let i2 = unsafe { inion.inion }; + let _r1 = u2 - u1 - m1; + let _r2 = i1 + i2 + m2; + let _u8 = unsafe { union.u8ion }; + let _i64 = unsafe { union.i64on }; + let _u64 = unsafe { union.u64on }; +} diff --git a/gcc/testsuite/rust/compile/torture/unit_type1.rs b/gcc/testsuite/rust/compile/torture/unit_type1.rs new file mode 100644 index 00000000000..d5f73575745 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unit_type1.rs @@ -0,0 +1,7 @@ +fn main() { + let a: () = (); + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + let b; + b = (); +} diff --git a/gcc/testsuite/rust/compile/torture/unit_type2.rs b/gcc/testsuite/rust/compile/torture/unit_type2.rs new file mode 100644 index 00000000000..b5f925907d8 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unit_type2.rs @@ -0,0 +1,8 @@ +fn test(a: ()) -> () { + a +} + +fn main() { + let a; + a = test(()); +} diff --git a/gcc/testsuite/rust/compile/torture/unit_type3.rs b/gcc/testsuite/rust/compile/torture/unit_type3.rs new file mode 100644 index 00000000000..d48a691046b --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unit_type3.rs @@ -0,0 +1,6 @@ +struct S; + +fn main() { + let s = S; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/unit_type4.rs b/gcc/testsuite/rust/compile/torture/unit_type4.rs new file mode 100644 index 00000000000..ccbfa21818a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unit_type4.rs @@ -0,0 +1,5 @@ +struct S; + +fn main() { + let _s = S {}; +} diff --git a/gcc/testsuite/rust/compile/torture/unit_type5.rs b/gcc/testsuite/rust/compile/torture/unit_type5.rs new file mode 100644 index 00000000000..3c4323aa73c --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unit_type5.rs @@ -0,0 +1,8 @@ +struct Foo; + +fn main() { + let a = Foo {}; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = Foo; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/unsafe1.rs b/gcc/testsuite/rust/compile/torture/unsafe1.rs new file mode 100644 index 00000000000..f57ef52b9c0 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unsafe1.rs @@ -0,0 +1,12 @@ +fn test() -> i32 { + unsafe { + let a; + a = 123; + a + } +} + +fn main() { + let a; + a = test(); +} diff --git a/gcc/testsuite/rust/compile/torture/unsafe2.rs b/gcc/testsuite/rust/compile/torture/unsafe2.rs new file mode 100644 index 00000000000..0b3aad53a44 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unsafe2.rs @@ -0,0 +1,4 @@ +fn main() { + unsafe {} + () +} diff --git a/gcc/testsuite/rust/compile/torture/unsafe3.rs b/gcc/testsuite/rust/compile/torture/unsafe3.rs new file mode 100644 index 00000000000..5f427258f60 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unsafe3.rs @@ -0,0 +1,9 @@ +pub fn test() -> i32 { + let a = unsafe { 123 }; + a +} + +pub fn main() { + let a = test(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/unsafe4.rs b/gcc/testsuite/rust/compile/torture/unsafe4.rs new file mode 100644 index 00000000000..6fe3101d49c --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unsafe4.rs @@ -0,0 +1,12 @@ +struct SS { + one: i32, + two: i32, +} +struct TS(i32, i32); + +fn main() { + unsafe { + let ss = SS { one: 1, two: 2 }; + let _ts = TS(ss.one, ss.two); + }; +} diff --git a/gcc/testsuite/rust/compile/torture/unused.rs b/gcc/testsuite/rust/compile/torture/unused.rs new file mode 100644 index 00000000000..d95e6b01c00 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unused.rs @@ -0,0 +1,17 @@ +// { dg-warning "function is never used: 'bar'" "" { target *-*-* } .+1 } +fn bar() { + foo(); +} + +// { dg-warning "function is never used: 'foo'" "" { target *-*-* } .+1 } +fn foo() { + bar(); +} + +fn f() { + +} + +fn main() { + f(); +} diff --git a/gcc/testsuite/rust/compile/torture/unused1.rs b/gcc/testsuite/rust/compile/torture/unused1.rs new file mode 100644 index 00000000000..db7eb8fc1fc --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unused1.rs @@ -0,0 +1,15 @@ +fn test() -> i32 { + 1 +} + +fn unused() -> i32 { + // { dg-warning "function is never used: 'unused'" "" { target *-*-* } .-1 } + 2 +} + +fn main() { + let a = 1; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + let b = test(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/unused_struct.rs b/gcc/testsuite/rust/compile/torture/unused_struct.rs new file mode 100644 index 00000000000..ba9ec3250cf --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unused_struct.rs @@ -0,0 +1,7 @@ +struct Foo { + // { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + one: i32, + two: i32, +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/torture/unused_struct_field.rs b/gcc/testsuite/rust/compile/torture/unused_struct_field.rs new file mode 100644 index 00000000000..429b3039da4 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unused_struct_field.rs @@ -0,0 +1,9 @@ +struct Foo { + one: i32, +// { dg-warning "field is never read" "" { target *-*-* } .-1 } + two: i32 +} +fn main() { + let _a = Foo {one: 1, two: 2}; + let _b = _a.two; +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/usize1.rs b/gcc/testsuite/rust/compile/torture/usize1.rs new file mode 100644 index 00000000000..ba1d5c60320 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/usize1.rs @@ -0,0 +1,6 @@ +fn main() { + let a = [1, 2, 3]; + let b: usize = 1; + let c = a[b]; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/torture/very-broken-attr-string.rs b/gcc/testsuite/rust/compile/torture/very-broken-attr-string.rs new file mode 100644 index 00000000000..832ba7b8ec9 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/very-broken-attr-string.rs @@ -0,0 +1,3 @@ +// { dg-excess-errors "...." } +// { dg-error "unended string literal" "" { target *-*-* } .+1 } +#[doc(alias = "123 diff --git a/gcc/testsuite/rust/compile/torture/while_function.rs b/gcc/testsuite/rust/compile/torture/while_function.rs new file mode 100644 index 00000000000..014db902769 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/while_function.rs @@ -0,0 +1,10 @@ +fn foo() {} +fn bar() -> i32 { return 10; } + +fn main() { + let mut i = 1; + while i < bar() { + foo(); + i += 1; + } +} diff --git a/gcc/testsuite/rust/compile/traits1.rs b/gcc/testsuite/rust/compile/traits1.rs new file mode 100644 index 00000000000..355064eec1a --- /dev/null +++ b/gcc/testsuite/rust/compile/traits1.rs @@ -0,0 +1,13 @@ +trait Foo { + fn Bar() -> i32 {} + // { dg-error "expected .i32. got .()." "" { target *-*-* } .-1 } +} + +struct Baz; + +impl Foo for Baz { + fn Barrr() {} + // { dg-error "method .Barrr. is not a member of trait .Foo." "" { target *-*-* } .-1 } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/traits10.rs b/gcc/testsuite/rust/compile/traits10.rs new file mode 100644 index 00000000000..f8f551ba86d --- /dev/null +++ b/gcc/testsuite/rust/compile/traits10.rs @@ -0,0 +1,15 @@ +struct Foo(i32); + +trait Bar { + const A: i32 = 123; + fn B(); + fn C(&self); +} + +pub fn main() { + let a; + a = Foo(123); + + let b: &dyn Bar = &a; + // { dg-error "trait bound is not object safe" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/traits11.rs b/gcc/testsuite/rust/compile/traits11.rs new file mode 100644 index 00000000000..d06e47d7e16 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits11.rs @@ -0,0 +1,19 @@ +struct Foo(i32); + +trait A { + const A: i32 = 123; + fn B(); + fn C(&self); +} + +trait B: A { + fn test(&self); +} + +pub fn main() { + let a; + a = Foo(123); + + let b: &dyn B = &a; + // { dg-error "trait bound is not object safe" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/traits12.rs b/gcc/testsuite/rust/compile/traits12.rs new file mode 100644 index 00000000000..25e0eb7aaa3 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits12.rs @@ -0,0 +1,20 @@ +trait A { + type Output; + + fn test(self, a: &T) -> &Self::Output; +} + +struct Foo { + start: T, + end: T, +} + +impl A for Foo { + // { dg-error "generic item takes at least 1 type arguments but 0 were supplied" "" { target *-*-* } .-1 } + // { dg-error "unconstrained type parameter" "" { target *-*-* } .-2 } + type Output = T; + + fn test(self, a: &T) -> &Self::Output { + a + } +} diff --git a/gcc/testsuite/rust/compile/traits2.rs b/gcc/testsuite/rust/compile/traits2.rs new file mode 100644 index 00000000000..7357c22f7d6 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits2.rs @@ -0,0 +1,14 @@ +trait Foo { + fn Bar() -> i32 {} + // { dg-error "expected .i32. got .()." "" { target *-*-* } .-1 } +} + +struct Baz; + +impl Foo for Baz { + fn Bar() {} + // { dg-error "expected .i32. got .()." "" { target *-*-* } .-1 } + // { dg-error "method .Bar. has an incompatible type for trait .Foo." "" { target *-*-* } .-2 } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/traits3.rs b/gcc/testsuite/rust/compile/traits3.rs new file mode 100644 index 00000000000..fd3fa457cc8 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits3.rs @@ -0,0 +1,22 @@ +trait Foo { + type A; + + fn baz(a: Self::A) -> Self::A; +} + +struct Bar(T); + +impl Foo for Bar { + type A = i32; + + fn baz(a: f32) -> f32 { + // { dg-error "method .baz. has an incompatible type for trait .Foo." "" { target *-*-* } .-1 } + a + // { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 } + } +} + +fn main() { + let a; + a = Bar::::baz(123f32); +} diff --git a/gcc/testsuite/rust/compile/traits4.rs b/gcc/testsuite/rust/compile/traits4.rs new file mode 100644 index 00000000000..486301d6136 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits4.rs @@ -0,0 +1,16 @@ +trait Foo { + const A: i32; + + fn test(self); +} + +struct Bar; +impl Foo for Bar { + // { dg-error "missing A in implementation of trait .Foo." "" { target *-*-* } .-1 } + fn test(self) {} +} + +fn main() { + let a = Bar; + a.test(); +} diff --git a/gcc/testsuite/rust/compile/traits5.rs b/gcc/testsuite/rust/compile/traits5.rs new file mode 100644 index 00000000000..8b2fb9bc10d --- /dev/null +++ b/gcc/testsuite/rust/compile/traits5.rs @@ -0,0 +1,9 @@ +trait Foo { + const A: i32; + + fn test(self); +} + +struct Bar; +impl Foo for Bar {} +// { dg-error "missing A, test in implementation of trait .Foo." "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/traits6.rs b/gcc/testsuite/rust/compile/traits6.rs new file mode 100644 index 00000000000..3579b5a0842 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits6.rs @@ -0,0 +1,15 @@ +trait Foo { + fn default() -> i32; +} + +struct Bar(i32); + +fn type_bound_test() -> i32 { + T::default() +} + +fn main() { + let a; + a = type_bound_test::(); + // { dg-error "bounds not satisfied for Bar" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/traits7.rs b/gcc/testsuite/rust/compile/traits7.rs new file mode 100644 index 00000000000..825553ce496 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits7.rs @@ -0,0 +1,24 @@ +trait Foo { + fn default() -> i32; +} + +trait Bar { + fn not_default() -> i32; +} + +struct Test(i32); + +impl Foo for Test { + fn default() -> i32 { + 1234 + } +} + +fn type_bound_test() -> i32 { + T::default() +} + +fn main() { + let a = type_bound_test::(); + // { dg-error "bounds not satisfied for Test" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/traits8.rs b/gcc/testsuite/rust/compile/traits8.rs new file mode 100644 index 00000000000..b22590a52bb --- /dev/null +++ b/gcc/testsuite/rust/compile/traits8.rs @@ -0,0 +1,35 @@ +trait A { + fn get(self) -> f64; +} + +trait B { + fn get(self) -> u8; +} + +struct Foo(u8, f64); + +impl A for Foo { + fn get(self) -> f64 { + self.1 + } +} + +impl B for Foo { + fn get(self) -> u8 { + self.0 + } +} + +fn main() { + let _a; + _a = Foo(123, 456f64); + + let _b: f64; + _b = ::get(_a); + + let _a; + _a = Foo(123, 456f64); + + let _c: u8; + _c = ::get(_a) +} diff --git a/gcc/testsuite/rust/compile/traits9.rs b/gcc/testsuite/rust/compile/traits9.rs new file mode 100644 index 00000000000..e1aef5397fc --- /dev/null +++ b/gcc/testsuite/rust/compile/traits9.rs @@ -0,0 +1,13 @@ +struct Foo(i32); +trait Bar { + fn baz(&self); +} + +fn main() { + let a; + a = Foo(123); + + let b: &dyn Bar = &a; + // { dg-error "bounds not satisfied for Foo .Bar. is not satisfied" "" { target *-*-* } .-1 } + // { dg-error "expected" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/tuple1.rs b/gcc/testsuite/rust/compile/tuple1.rs new file mode 100644 index 00000000000..84179b13727 --- /dev/null +++ b/gcc/testsuite/rust/compile/tuple1.rs @@ -0,0 +1,5 @@ +fn main() { + let a: (i32, bool) = (123, 123); // { dg-error "expected .bool. got .." } + let b; + b = (456, 5f32); +} diff --git a/gcc/testsuite/rust/compile/tuple_struct1.rs b/gcc/testsuite/rust/compile/tuple_struct1.rs new file mode 100644 index 00000000000..2f4cb4a353b --- /dev/null +++ b/gcc/testsuite/rust/compile/tuple_struct1.rs @@ -0,0 +1,8 @@ +struct Foo { + one: i32, + two: i32, +} + +fn main() { + let a = Foo(1, 2); // { dg-error "expected function, tuple struct or tuple variant, found struct 'Foo'" } +} diff --git a/gcc/testsuite/rust/compile/tuple_struct2.rs b/gcc/testsuite/rust/compile/tuple_struct2.rs new file mode 100644 index 00000000000..1fc18968577 --- /dev/null +++ b/gcc/testsuite/rust/compile/tuple_struct2.rs @@ -0,0 +1,5 @@ +struct Bar(i32, i32, bool); + +fn main() { + let a = Bar(1, 2); // { dg-error "unexpected number of arguments 2 expected 3" } +} diff --git a/gcc/testsuite/rust/compile/tuple_struct3.rs b/gcc/testsuite/rust/compile/tuple_struct3.rs new file mode 100644 index 00000000000..4af66b8370e --- /dev/null +++ b/gcc/testsuite/rust/compile/tuple_struct3.rs @@ -0,0 +1,6 @@ +struct Foo(i32, i32, bool); + +fn main() { + let c = Foo(1, 2f32, true); + // { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/type-alias1.rs b/gcc/testsuite/rust/compile/type-alias1.rs new file mode 100644 index 00000000000..c7d7048246a --- /dev/null +++ b/gcc/testsuite/rust/compile/type-alias1.rs @@ -0,0 +1,6 @@ +type TypeAlias = (i32, u32); + +fn main() { + let a: TypeAlias; + a = (123, 456f32); // { dg-error "expected .u32. got .f32." } +} diff --git a/gcc/testsuite/rust/compile/type-bindings1.rs b/gcc/testsuite/rust/compile/type-bindings1.rs new file mode 100644 index 00000000000..ad85ed97ecb --- /dev/null +++ b/gcc/testsuite/rust/compile/type-bindings1.rs @@ -0,0 +1,10 @@ +struct Foo(A, B); + +fn main() { + let a; + a = Foo::(123f32); + // { dg-error "associated type bindings are not allowed here" "" { target *-*-* } .-1 } + // { dg-error {failed to type resolve expression} "" { target *-*-* } .-2 } + // { dg-error {Failed to resolve expression of function call} "" { target *-*-* } .-3 } + // { duplicate _dg-error {failed to type resolve expression} "" { target *-*-* } .-4 } +} diff --git a/gcc/testsuite/rust/compile/unary_negation.rs b/gcc/testsuite/rust/compile/unary_negation.rs new file mode 100644 index 00000000000..848643f0bd2 --- /dev/null +++ b/gcc/testsuite/rust/compile/unary_negation.rs @@ -0,0 +1,9 @@ +fn main() { + let a: i32 = -1; + let b: i32 = 3 - -1; + let c: bool = !false; + let d: i32 = !3; + + let e: f32 = -true; // // { dg-error "cannot apply unary - to bool" } + // { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/unary_not.rs b/gcc/testsuite/rust/compile/unary_not.rs new file mode 100644 index 00000000000..b0a3dafbbd0 --- /dev/null +++ b/gcc/testsuite/rust/compile/unary_not.rs @@ -0,0 +1,9 @@ +fn main() { + let a: i32 = -1; + let b: i32 = 3 - -1; + let c: bool = !false; + let d: i32 = !3; + + let e: f32 = !5f32; // { dg-error "cannot apply unary '!' to f32" } + // { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/unconstrained_type_param.rs b/gcc/testsuite/rust/compile/unconstrained_type_param.rs new file mode 100644 index 00000000000..c4aaa10146f --- /dev/null +++ b/gcc/testsuite/rust/compile/unconstrained_type_param.rs @@ -0,0 +1,12 @@ +struct Foo(T, bool); + +impl Foo { + // { dg-error "unconstrained type parameter" "" { target *-*-* } .-1 } + fn test() -> Y { + 123 + } +} + +fn main() { + let a = Foo::test(); +} diff --git a/gcc/testsuite/rust/compile/unicode_escape.rs b/gcc/testsuite/rust/compile/unicode_escape.rs new file mode 100644 index 00000000000..39b91d8a95c --- /dev/null +++ b/gcc/testsuite/rust/compile/unicode_escape.rs @@ -0,0 +1,60 @@ +fn main () +{ + // Braces are required + let _cbl = '\u013'; // { dg-error "unicode escape" } + let _sbl = "\u013"; //{ dg-error "unicode escape" } + + // One to six hex digits + let _c0 = '\u{}'; // { dg-error "unicode escape" } + let _c1 = '\u{0}'; + let _c2 = '\u{00}'; + let _c3 = '\u{000}'; + let _c4 = '\u{0000}'; + let _c5 = '\u{00000}'; + let _c6 = '\u{000000}'; + let _c7 = '\u{0000000}'; // { dg-error "unicode escape" } + + let _s0 = "\u{}"; // { dg-error "unicode escape" } + let _s1 = "\u{0}"; + let _s2 = "\u{00}"; + let _s3 = "\u{000}"; + let _s4 = "\u{0000}"; + let _s5 = "\u{00000}"; + let _s6 = "\u{000000}"; + let _s7 = "\u{0000000}"; // { dg-error "unicode escape" } + + // Underscores OK except for start + let _c_ = '\u{00___01__0_1_}'; + let _s_ = "\u{00___01__0_1_}"; + let _c__ = '\u{_00__01__0_}'; // { dg-error "unicode escape" } + let _s__ = "\u{_00__01__0_}"; // { dg-error "unicode escape" } + + // Must be hex chars + let _chex = '\u{hex}'; // { dg-error "unicode escape" } + let _shex = '\u{hex}'; // { dg-error "unicode escape" } + + // Only valid from 0x0 to 0xD7FF and from 0xE000 to 0x10FFF + let _cd7ff = '\u{D7FF}'; + let _sd7ff = "\u{D7FF}"; + let _cd800 = '\u{D800}'; // { dg-error "unicode escape" } + let _sd800 = "\u{D800}"; // { dg-error "unicode escape" } + + let _cdfff = '\u{DFFF}'; // { dg-error "unicode escape" } + let _sdfff = "\u{DFFF}"; // { dg-error "unicode escape" } + let _ce000 = '\u{E000}'; + let _se000 = "\u{E000}"; + + let _clast = '\u{10FFFF}'; + let _slast = "\u{10FFFF}"; + let _clast1 = '\u{110000}'; // { dg-error "unicode escape" } + let _slast1 = "\u{110000}"; // { dg-error "unicode escape" } + + let _cffffff = '\u{FFFFFF}'; // { dg-error "unicode escape" } + let _sffffff = "\u{FFFFFF}"; // { dg-error "unicode escape" } + + // unicode escapes cannot be used in bytes or byte strings. + // Except in raw byte strings (where they aren't escapes). + let _bc = b'\u{000A}'; // { dg-error "unicode escape" } + let _bs = b"\u{000A}"; // { dg-error "unicode escape" } + let _rbs = br"\u{000A}"; +} diff --git a/gcc/testsuite/rust/compile/unsafe1.rs b/gcc/testsuite/rust/compile/unsafe1.rs new file mode 100644 index 00000000000..9cd3f6b4bf2 --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe1.rs @@ -0,0 +1,14 @@ +fn foo(_a: &i32) {} +fn bar(_a: i32) {} + +static mut a: i32 = 15; + +fn main() { + foo(&a); // { dg-error "use of mutable static" } + bar(a); // { dg-error "use of mutable static" } + + unsafe { + foo(&a); + bar(a); + } +} diff --git a/gcc/testsuite/rust/compile/unsafe10.rs b/gcc/testsuite/rust/compile/unsafe10.rs new file mode 100644 index 00000000000..6b6be06b908 --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe10.rs @@ -0,0 +1,12 @@ +extern "rust-intrinsic" { + pub fn rotate_left(l: T, r: T) -> T; +} + +fn main() -> i32 { + let a = 15; + let b = 15; + + let _ = rotate_left(a, b); + + 0 +} diff --git a/gcc/testsuite/rust/compile/unsafe2.rs b/gcc/testsuite/rust/compile/unsafe2.rs new file mode 100644 index 00000000000..e03e4bc59f4 --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe2.rs @@ -0,0 +1,16 @@ +fn foo(_a: &i32) {} +fn bar(_a: i32) {} + +mod inner { + pub static mut a: i32 = 15; +} + +fn main() { + foo(&inner::a); // { dg-error "use of mutable static" } + bar(inner::a); // { dg-error "use of mutable static" } + + unsafe { + foo(&inner::a); + bar(inner::a); + } +} diff --git a/gcc/testsuite/rust/compile/unsafe3.rs b/gcc/testsuite/rust/compile/unsafe3.rs new file mode 100644 index 00000000000..56aec76008a --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe3.rs @@ -0,0 +1,10 @@ +extern "C" { + static VALUE: char; +} + +fn main() { + let _ = VALUE; // { dg-error "use of extern static" } + unsafe { + let _ = VALUE; + } +} diff --git a/gcc/testsuite/rust/compile/unsafe4.rs b/gcc/testsuite/rust/compile/unsafe4.rs new file mode 100644 index 00000000000..7d1356bc3e5 --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe4.rs @@ -0,0 +1,29 @@ +fn foo() -> i32 { + let a = 15; + let p_a = &a as *const i32; + + unsafe { *p_a } +} + +unsafe fn bar() -> i32 { + let a = 15; + let p_a = &a as *const i32; + + *p_a +} + +fn baz() -> i32 { + let a = 15; + let p_a = &a as *const i32; + + *p_a // { dg-error "dereference of raw pointer" } +} + +unsafe fn qux() -> i32 { + let a = 15; + let p_a = &a as *const i32; + + unsafe {} + + *p_a +} diff --git a/gcc/testsuite/rust/compile/unsafe5.rs b/gcc/testsuite/rust/compile/unsafe5.rs new file mode 100644 index 00000000000..35990f6ee9f --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe5.rs @@ -0,0 +1,4 @@ +fn main() { + let b = 15; + let c = *(&b as *const i32); // { dg-error "dereference of raw pointer" } +} diff --git a/gcc/testsuite/rust/compile/unsafe6.rs b/gcc/testsuite/rust/compile/unsafe6.rs new file mode 100644 index 00000000000..cf4b75456e4 --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe6.rs @@ -0,0 +1,14 @@ +unsafe fn foo() {} +unsafe fn bar() { + foo(); +} + +fn main() { + foo(); // { dg-error "call to unsafe function" } + bar(); // { dg-error "call to unsafe function" } + + unsafe { + foo(); + bar(); + } +} diff --git a/gcc/testsuite/rust/compile/unsafe7.rs b/gcc/testsuite/rust/compile/unsafe7.rs new file mode 100644 index 00000000000..a6b69e1ac37 --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe7.rs @@ -0,0 +1,9 @@ +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn main() { + let s = "hey\0"; + + printf(s as *const str as *const i8); // { dg-error "call to extern function" } +} diff --git a/gcc/testsuite/rust/compile/unsafe8.rs b/gcc/testsuite/rust/compile/unsafe8.rs new file mode 100644 index 00000000000..03fe4910c97 --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe8.rs @@ -0,0 +1,14 @@ +struct S; + +impl S { + unsafe fn foo(self) {} +} + +fn main() { + let s = S; + s.foo(); // { dg-error "call to unsafe method" } + + unsafe { + s.foo(); + } +} diff --git a/gcc/testsuite/rust/compile/unsafe9.rs b/gcc/testsuite/rust/compile/unsafe9.rs new file mode 100644 index 00000000000..fb46c8ffde3 --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe9.rs @@ -0,0 +1,10 @@ +union U { + a: i32, + b: f32, + c: u8, +} + +fn main() { + let u = U { a: 14 }; + let _ = u.a; // { dg-error "access to union" } +} diff --git a/gcc/testsuite/rust/compile/unterminated_c_comment.rs b/gcc/testsuite/rust/compile/unterminated_c_comment.rs new file mode 100644 index 00000000000..619b7b7024d --- /dev/null +++ b/gcc/testsuite/rust/compile/unterminated_c_comment.rs @@ -0,0 +1,2 @@ +// { dg-error "unexpected EOF while looking for end of comment" "" { target *-*-* } .+1 } +/* This comment needs closure :) ! diff --git a/gcc/testsuite/rust/compile/use_1.rs b/gcc/testsuite/rust/compile/use_1.rs new file mode 100644 index 00000000000..94b96321a63 --- /dev/null +++ b/gcc/testsuite/rust/compile/use_1.rs @@ -0,0 +1,16 @@ +mod frob {} + +use foo::bar::baz; // { dg-error "cannot find simple path segment .foo." } +use frob::ulator; // { dg-error "cannot find simple path segment .ulator." } + +mod sain { + mod doux {} + + mod dron {} +} + +use not_sain::*; // { dg-error "cannot find simple path segment .not_sain." } + +use sain::*; +use sain::{doux, dron}; +use sain::{doux, dron, graal}; // { dg-error "cannot find simple path segment .graal." } diff --git a/gcc/testsuite/rust/compile/usize1.rs b/gcc/testsuite/rust/compile/usize1.rs new file mode 100644 index 00000000000..b1c8fe86473 --- /dev/null +++ b/gcc/testsuite/rust/compile/usize1.rs @@ -0,0 +1,6 @@ +fn main() { + let a = [1, 2, 3]; + let b: u32 = 1; + let c = a[b]; // { dg-error "the type ...integer..CAPACITY.. cannot be indexed by .u32." } + // { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/xfail/lifetime_param.rs b/gcc/testsuite/rust/compile/xfail/lifetime_param.rs new file mode 100644 index 00000000000..306fca0b3c5 --- /dev/null +++ b/gcc/testsuite/rust/compile/xfail/lifetime_param.rs @@ -0,0 +1,11 @@ +// { dg-excess-errors "warnings" } + +// { dg-error "lifetime not defined" "#359" { xfail *-*-* } .+1 } +fn lifetime_undefined(t: &'a str) -> &'a str { + t +} + +// { dg-error "lifetime not defined" "#359" { xfail *-*-* } .+1 } +fn lifetime_undefined_bis<'a>(t: &'a str)-> &'b str { + t +} diff --git a/gcc/testsuite/rust/compile/xfail/struct_field_vis.rs b/gcc/testsuite/rust/compile/xfail/struct_field_vis.rs new file mode 100644 index 00000000000..a28729e6208 --- /dev/null +++ b/gcc/testsuite/rust/compile/xfail/struct_field_vis.rs @@ -0,0 +1,15 @@ +// { dg-xfail-if "pub visibility not supported #432" *-*-* } + +mod foomod { + pub struct Foo { + pub f: i32, + pub g: u32, + } +} + +fn test() -> foomod::Foo { + foomod::Foo{ + f:1, + g:3, + } +} diff --git a/gcc/testsuite/rust/compile/xfail/xfail.exp b/gcc/testsuite/rust/compile/xfail/xfail.exp new file mode 100644 index 00000000000..5fb6203bb31 --- /dev/null +++ b/gcc/testsuite/rust/compile/xfail/xfail.exp @@ -0,0 +1,63 @@ +# Copyright (C) 2021-2022 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 +# . + +# Compile tests, no torture testing. +# +# These tests are used to keep track of known limitations : +# 1- tests that are incorrecly build instead of being rejected +# 2- tests that are build to an incorrect result +# 3- tests that are rejected instead of being correctly build +# +# Not currently supported here: +# - tests that are exhibiting incorrect behavior at runtime +# +# Here's how to annotate tests for each cases: +# +# 1- test is successfuly build instead of being rejected +# +# Expected behavior: a specific error rejecting the test +# Observed behavior: error not present +# Use dg-error and mark the test xfail and add reference to corresponding issue. +# { dg-error "lifetime not defined" "#359" { xfail *-*-* } } +# +# 2- test is successfuly build but result is incorrect +# +# Expected behavior: test is correctly build and has specific property +# Observed behavior: test is correctly build but is missing the specific property +# Depends on the property. For example, if the property can be checked in the assembly file, use dg-final + xfail. +# { dg-final { scan-assembler "given_string_missing_in_assembly_" "#1234" { xfail *-*-* } } } +# +# 3- test is rejected instead of being correctly build +# +# Expected behavior: test is successfully build +# Observed behavior: the test is rejected with an error +# Use dg-bogus + xfail to match the bogus error message, or use dg-xfail-if if it's harder to match a specific error. + +# Load support procs. +load_lib rust-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +set saved-dg-do-what-default ${dg-do-what-default} + +set dg-do-what-default "compile" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" "" +set dg-do-what-default ${saved-dg-do-what-default} + +# All done. +dg-finish From patchwork Tue Dec 6 10:13:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61501 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D71CF3AA8429 for ; Tue, 6 Dec 2022 10:12:51 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by sourceware.org (Postfix) with ESMTPS id BE24A395B403 for ; Tue, 6 Dec 2022 10:11:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org BE24A395B403 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x435.google.com with SMTP id bs21so22754530wrb.4 for ; Tue, 06 Dec 2022 02:11:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=5PljxI7rBNmdAQGq+pbvdYLoVSRtnSGKolVO6Xfzc9Y=; b=GLY/uodk18XB0fFLldTOmE/pjfXlNrGQOYL0AvDm1u3+kB+T+oSQDjbC6ZnHv2YYFV oJuvrWfTiV4BW795ihKR+Uxmy51igyteWGJi2Rcbyv1WekXCQdmGmRc4UYImmiLgrSyw 8vwV9vDaqCs3FioDkthG+MfzVjaz16+r2I/PxbiPvZAu6TGpgVHYdVIroF9CjDiygdgB hVZejXb1AVqECBtqgv9RMnbB6BGFo+YfdkiJDapAQakHru8p8kkQKQ7zK5sD6ZsUo51B 5vq/t0kblgxVt2VU8Uqa2eGNsK5BnhqWMPENzOqp8fJlaOXuo759DnCieRFwnTNVvY1S kjxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=5PljxI7rBNmdAQGq+pbvdYLoVSRtnSGKolVO6Xfzc9Y=; b=nFPwMUxgaqIcA7gLdbP56Y/B3pvDpRneuDupgdU/+16+rxHgpTK+Mg2MtIjn40FqKV xqp6HBx9twfbN3bUVvJdH9B1pN5dxadjXyHwjr68NZuir2KMX016c4EDzywfe6hIGpf4 ibCzWhk2un35aMH8/Xye0oKNtQ8y5ZOIvpNkRISNTtzOaOjwCJ7VnNlMe3hMl/rPeney /fLFA6S4pcN/7TAKEjGaM01Jc2PkJMEwPzV0aYow9HOTfPW3xnavqFqx1GJddtpV15xl DuGUgWZkpXuYVj9qhjYhnaLFP50WV6gSixDMsvEQqcynXhVYQroBE2AlNHaiA9n9sZ/7 0ofQ== X-Gm-Message-State: ANoB5pksqTLjTbGtXI2HIJl7fbkVSQsnabOLZC7oy1S9mFYnFO5Me6W/ abAVuFG/wOVlLO7nFeAD5t/Zm6adjrWlAUHtag== X-Google-Smtp-Source: AA0mqf7xI6N2hAxZeaJG8YupkdfNF641jd6yPRAcQe3WI9iIp+Ta3gvRfR5SE2FL8IeLQfXPlD0cUw== X-Received: by 2002:adf:f98e:0:b0:242:324:ff88 with SMTP id f14-20020adff98e000000b002420324ff88mr31751728wrr.81.1670321513685; Tue, 06 Dec 2022 02:11:53 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.11.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:11:53 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Philip Herron , Arthur Cohen , Thomas Schwinge , Mark Wielaard , =?utf-8?q?Marc_Poulhi=C3=A8s?= Subject: [PATCH Rust front-end v4 06/46] gccrs: Add execution test cases Date: Tue, 6 Dec 2022 11:13:38 +0100 Message-Id: <20221206101417.778807-7-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-30.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This is similar to the compile/torture/*.rs test cases, but all of these are dg-execute testcases. They are compiled, linked and executed by default. These testcases are also compiled with the matrix of torture options. The only caveat here is that gccrs does not currently support the main shim, so we have a C-style main function here returning zero which is not proper Rust code. Co-authored-by: Arthur Cohen Co-authored-by: Thomas Schwinge Co-authored-by: Mark Wielaard Co-authored-by: Marc Poulhiès --- .../rust/execute/torture/block_expr1.rs | 8 + .../rust/execute/torture/builtin_macro_cfg.rs | 32 ++++ .../execute/torture/builtin_macro_concat.rs | 29 +++ .../rust/execute/torture/builtin_macro_env.rs | 31 ++++ .../torture/builtin_macro_include_bytes.rs | 46 +++++ .../torture/builtin_macro_include_str.rs | 27 +++ .../execute/torture/builtin_macro_line.rs | 25 +++ .../rust/execute/torture/builtin_macros1.rs | 21 +++ .../rust/execute/torture/builtin_macros3.rs | 28 +++ gcc/testsuite/rust/execute/torture/cfg1.rs | 32 ++++ gcc/testsuite/rust/execute/torture/cfg2.rs | 31 ++++ gcc/testsuite/rust/execute/torture/cfg3.rs | 37 ++++ gcc/testsuite/rust/execute/torture/cfg4.rs | 38 ++++ gcc/testsuite/rust/execute/torture/cfg5.rs | 13 ++ .../rust/execute/torture/coercion1.rs | 41 +++++ .../rust/execute/torture/coercion2.rs | 39 ++++ .../rust/execute/torture/const_fold1.rs | 13 ++ .../rust/execute/torture/const_fold2.rs | 16 ++ .../execute/torture/copy_nonoverlapping1.rs | 17 ++ .../rust/execute/torture/empty_main.rs | 3 + .../rust/execute/torture/execute.exp | 33 ++++ .../rust/execute/torture/exit_error.rs | 5 + .../rust/execute/torture/extern_mod4.rs | 19 ++ gcc/testsuite/rust/execute/torture/func1.rs | 5 + .../rust/execute/torture/helloworld1.rs | 15 ++ .../rust/execute/torture/helloworld2.rs | 15 ++ .../rust/execute/torture/include.txt | 1 + gcc/testsuite/rust/execute/torture/index1.rs | 28 +++ .../rust/execute/torture/issue-1120.rs | 123 +++++++++++++ .../rust/execute/torture/issue-1133.rs | 146 +++++++++++++++ .../rust/execute/torture/issue-1198.rs | 75 ++++++++ .../rust/execute/torture/issue-1231.rs | 36 ++++ .../rust/execute/torture/issue-1232.rs | 159 ++++++++++++++++ .../rust/execute/torture/issue-1249.rs | 39 ++++ .../rust/execute/torture/issue-1436.rs | 172 ++++++++++++++++++ .../rust/execute/torture/issue-1496.rs | 75 ++++++++ .../rust/execute/torture/issue-647.rs | 33 ++++ .../rust/execute/torture/issue-845.rs | 47 +++++ .../rust/execute/torture/issue-851.rs | 35 ++++ .../rust/execute/torture/issue-858.rs | 32 ++++ .../rust/execute/torture/issue-976.rs | 14 ++ .../rust/execute/torture/issue-995.rs | 9 + gcc/testsuite/rust/execute/torture/macros1.rs | 13 ++ .../rust/execute/torture/macros10.rs | 22 +++ .../rust/execute/torture/macros11.rs | 25 +++ .../rust/execute/torture/macros12.rs | 22 +++ .../rust/execute/torture/macros13.rs | 22 +++ .../rust/execute/torture/macros14.rs | 22 +++ .../rust/execute/torture/macros16.rs | 14 ++ .../rust/execute/torture/macros17.rs | 17 ++ .../rust/execute/torture/macros18.rs | 14 ++ .../rust/execute/torture/macros19.rs | 14 ++ gcc/testsuite/rust/execute/torture/macros2.rs | 40 ++++ .../rust/execute/torture/macros20.rs | 14 ++ .../rust/execute/torture/macros21.rs | 15 ++ .../rust/execute/torture/macros22.rs | 27 +++ .../rust/execute/torture/macros23.rs | 19 ++ .../rust/execute/torture/macros24.rs | 9 + .../rust/execute/torture/macros25.rs | 13 ++ .../rust/execute/torture/macros26.rs | 12 ++ .../rust/execute/torture/macros27.rs | 24 +++ .../rust/execute/torture/macros28.rs | 13 ++ .../rust/execute/torture/macros29.rs | 24 +++ gcc/testsuite/rust/execute/torture/macros3.rs | 61 +++++++ .../rust/execute/torture/macros30.rs | 25 +++ .../rust/execute/torture/macros31.rs | 32 ++++ gcc/testsuite/rust/execute/torture/macros4.rs | 15 ++ gcc/testsuite/rust/execute/torture/macros5.rs | 13 ++ gcc/testsuite/rust/execute/torture/macros6.rs | 12 ++ gcc/testsuite/rust/execute/torture/macros7.rs | 28 +++ gcc/testsuite/rust/execute/torture/macros8.rs | 27 +++ gcc/testsuite/rust/execute/torture/macros9.rs | 28 +++ gcc/testsuite/rust/execute/torture/match1.rs | 58 ++++++ gcc/testsuite/rust/execute/torture/match2.rs | 41 +++++ gcc/testsuite/rust/execute/torture/match3.rs | 51 ++++++ .../rust/execute/torture/match_bool1.rs | 49 +++++ .../rust/execute/torture/match_byte1.rs | 56 ++++++ .../rust/execute/torture/match_char1.rs | 56 ++++++ .../rust/execute/torture/match_int1.rs | 109 +++++++++++ .../rust/execute/torture/match_loop1.rs | 56 ++++++ .../rust/execute/torture/match_range1.rs | 37 ++++ .../rust/execute/torture/match_range2.rs | 45 +++++ .../rust/execute/torture/match_tuple1.rs | 45 +++++ gcc/testsuite/rust/execute/torture/method1.rs | 27 +++ gcc/testsuite/rust/execute/torture/method2.rs | 76 ++++++++ gcc/testsuite/rust/execute/torture/method3.rs | 78 ++++++++ gcc/testsuite/rust/execute/torture/method4.rs | 78 ++++++++ gcc/testsuite/rust/execute/torture/mod1.rs | 21 +++ .../rust/execute/torture/modules/mod.rs | 3 + .../execute/torture/operator_overload_1.rs | 36 ++++ .../execute/torture/operator_overload_10.rs | 75 ++++++++ .../execute/torture/operator_overload_11.rs | 37 ++++ .../execute/torture/operator_overload_12.rs | 31 ++++ .../execute/torture/operator_overload_2.rs | 38 ++++ .../execute/torture/operator_overload_3.rs | 55 ++++++ .../execute/torture/operator_overload_4.rs | 33 ++++ .../execute/torture/operator_overload_5.rs | 33 ++++ .../execute/torture/operator_overload_6.rs | 37 ++++ .../execute/torture/operator_overload_7.rs | 42 +++++ .../execute/torture/operator_overload_8.rs | 58 ++++++ .../execute/torture/operator_overload_9.rs | 58 ++++++ .../rust/execute/torture/slice-magic.rs | 106 +++++++++++ .../rust/execute/torture/slice-magic2.rs | 106 +++++++++++ gcc/testsuite/rust/execute/torture/slice1.rs | 27 +++ .../rust/execute/torture/str-layout1.rs | 57 ++++++ .../rust/execute/torture/str-zero.rs | 26 +++ gcc/testsuite/rust/execute/torture/trait1.rs | 52 ++++++ gcc/testsuite/rust/execute/torture/trait10.rs | 41 +++++ gcc/testsuite/rust/execute/torture/trait11.rs | 38 ++++ gcc/testsuite/rust/execute/torture/trait12.rs | 38 ++++ gcc/testsuite/rust/execute/torture/trait13.rs | 48 +++++ gcc/testsuite/rust/execute/torture/trait2.rs | 37 ++++ gcc/testsuite/rust/execute/torture/trait3.rs | 43 +++++ gcc/testsuite/rust/execute/torture/trait4.rs | 34 ++++ gcc/testsuite/rust/execute/torture/trait5.rs | 39 ++++ gcc/testsuite/rust/execute/torture/trait6.rs | 39 ++++ gcc/testsuite/rust/execute/torture/trait7.rs | 39 ++++ gcc/testsuite/rust/execute/torture/trait8.rs | 39 ++++ gcc/testsuite/rust/execute/torture/trait9.rs | 35 ++++ .../rust/execute/torture/transmute1.rs | 23 +++ .../rust/execute/torture/wrapping_op1.rs | 14 ++ .../rust/execute/torture/wrapping_op2.rs | 20 ++ gcc/testsuite/rust/execute/xfail/macro1.rs | 32 ++++ 123 files changed, 4631 insertions(+) create mode 100644 gcc/testsuite/rust/execute/torture/block_expr1.rs create mode 100644 gcc/testsuite/rust/execute/torture/builtin_macro_cfg.rs create mode 100644 gcc/testsuite/rust/execute/torture/builtin_macro_concat.rs create mode 100644 gcc/testsuite/rust/execute/torture/builtin_macro_env.rs create mode 100644 gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs create mode 100644 gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs create mode 100644 gcc/testsuite/rust/execute/torture/builtin_macro_line.rs create mode 100644 gcc/testsuite/rust/execute/torture/builtin_macros1.rs create mode 100644 gcc/testsuite/rust/execute/torture/builtin_macros3.rs create mode 100644 gcc/testsuite/rust/execute/torture/cfg1.rs create mode 100644 gcc/testsuite/rust/execute/torture/cfg2.rs create mode 100644 gcc/testsuite/rust/execute/torture/cfg3.rs create mode 100644 gcc/testsuite/rust/execute/torture/cfg4.rs create mode 100644 gcc/testsuite/rust/execute/torture/cfg5.rs create mode 100644 gcc/testsuite/rust/execute/torture/coercion1.rs create mode 100644 gcc/testsuite/rust/execute/torture/coercion2.rs create mode 100644 gcc/testsuite/rust/execute/torture/const_fold1.rs create mode 100644 gcc/testsuite/rust/execute/torture/const_fold2.rs create mode 100644 gcc/testsuite/rust/execute/torture/copy_nonoverlapping1.rs create mode 100644 gcc/testsuite/rust/execute/torture/empty_main.rs create mode 100644 gcc/testsuite/rust/execute/torture/execute.exp create mode 100644 gcc/testsuite/rust/execute/torture/exit_error.rs create mode 100644 gcc/testsuite/rust/execute/torture/extern_mod4.rs create mode 100644 gcc/testsuite/rust/execute/torture/func1.rs create mode 100644 gcc/testsuite/rust/execute/torture/helloworld1.rs create mode 100644 gcc/testsuite/rust/execute/torture/helloworld2.rs create mode 100644 gcc/testsuite/rust/execute/torture/include.txt create mode 100644 gcc/testsuite/rust/execute/torture/index1.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-1120.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-1133.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-1198.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-1231.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-1232.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-1249.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-1436.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-1496.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-647.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-845.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-851.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-858.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-976.rs create mode 100644 gcc/testsuite/rust/execute/torture/issue-995.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros1.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros10.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros11.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros12.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros13.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros14.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros16.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros17.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros18.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros19.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros2.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros20.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros21.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros22.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros23.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros24.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros25.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros26.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros27.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros28.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros29.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros3.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros30.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros31.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros4.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros5.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros6.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros7.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros8.rs create mode 100644 gcc/testsuite/rust/execute/torture/macros9.rs create mode 100644 gcc/testsuite/rust/execute/torture/match1.rs create mode 100644 gcc/testsuite/rust/execute/torture/match2.rs create mode 100644 gcc/testsuite/rust/execute/torture/match3.rs create mode 100644 gcc/testsuite/rust/execute/torture/match_bool1.rs create mode 100644 gcc/testsuite/rust/execute/torture/match_byte1.rs create mode 100644 gcc/testsuite/rust/execute/torture/match_char1.rs create mode 100644 gcc/testsuite/rust/execute/torture/match_int1.rs create mode 100644 gcc/testsuite/rust/execute/torture/match_loop1.rs create mode 100644 gcc/testsuite/rust/execute/torture/match_range1.rs create mode 100644 gcc/testsuite/rust/execute/torture/match_range2.rs create mode 100644 gcc/testsuite/rust/execute/torture/match_tuple1.rs create mode 100644 gcc/testsuite/rust/execute/torture/method1.rs create mode 100644 gcc/testsuite/rust/execute/torture/method2.rs create mode 100644 gcc/testsuite/rust/execute/torture/method3.rs create mode 100644 gcc/testsuite/rust/execute/torture/method4.rs create mode 100644 gcc/testsuite/rust/execute/torture/mod1.rs create mode 100644 gcc/testsuite/rust/execute/torture/modules/mod.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_1.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_10.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_11.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_12.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_2.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_3.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_4.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_5.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_6.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_7.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_8.rs create mode 100644 gcc/testsuite/rust/execute/torture/operator_overload_9.rs create mode 100644 gcc/testsuite/rust/execute/torture/slice-magic.rs create mode 100644 gcc/testsuite/rust/execute/torture/slice-magic2.rs create mode 100644 gcc/testsuite/rust/execute/torture/slice1.rs create mode 100644 gcc/testsuite/rust/execute/torture/str-layout1.rs create mode 100644 gcc/testsuite/rust/execute/torture/str-zero.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait1.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait10.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait11.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait12.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait13.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait2.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait3.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait4.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait5.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait6.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait7.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait8.rs create mode 100644 gcc/testsuite/rust/execute/torture/trait9.rs create mode 100644 gcc/testsuite/rust/execute/torture/transmute1.rs create mode 100644 gcc/testsuite/rust/execute/torture/wrapping_op1.rs create mode 100644 gcc/testsuite/rust/execute/torture/wrapping_op2.rs create mode 100644 gcc/testsuite/rust/execute/xfail/macro1.rs diff --git a/gcc/testsuite/rust/execute/torture/block_expr1.rs b/gcc/testsuite/rust/execute/torture/block_expr1.rs new file mode 100644 index 00000000000..d561f8cab59 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/block_expr1.rs @@ -0,0 +1,8 @@ +fn main() -> i32 { + let ret = { + 1; + 2; + 0 + }; + ret +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_cfg.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_cfg.rs new file mode 100644 index 00000000000..fad2daef6bc --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_macro_cfg.rs @@ -0,0 +1,32 @@ +// { dg-additional-options "-w -frust-cfg=A" } +// { dg-output "A\n" } +#[rustc_builtin_macro] +macro_rules! cfg { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: &str) { + unsafe { + printf( + "%s\n" as *const str as *const i8, + s as *const str as *const i8, + ); + } +} + +fn main() -> i32 { + let cfg = cfg!(A); + if cfg { + print("A"); + } + let cfg = cfg!(B); + if cfg { + print("B"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_concat.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_concat.rs new file mode 100644 index 00000000000..9b33924f5a1 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_macro_concat.rs @@ -0,0 +1,29 @@ +// { dg-output "\ntest10btrue2.15\ntest10bfalse2.151\n" } +#[rustc_builtin_macro] +macro_rules! concat { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: &str) { + unsafe { + printf( + "%s\n" as *const str as *const i8, + s as *const str as *const i8, + ); + } +} + +fn main() -> i32 { + let a = concat!(); + let b = concat!("test", 10, 'b', true, 2.15); + let c = concat!("test", 10, 'b', false, 2.15, 1u64); + print(a); + print(b); + print(c); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_env.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_env.rs new file mode 100644 index 00000000000..a5c80b25728 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_macro_env.rs @@ -0,0 +1,31 @@ +// { dg-output "VALUE\nVALUE\n" } +// { dg-set-compiler-env-var ENV_MACRO_TEST "VALUE" } +#[rustc_builtin_macro] +macro_rules! env { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: &str) { + unsafe { + printf( + "%s\n" as *const str as *const i8, + s as *const str as *const i8, + ); + } +} + +fn main() -> i32 { + let val0 = env!("ENV_MACRO_TEST"); + + print(val0); + + let val1 = env!("ENV_MACRO_TEST",); + + print(val1); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs new file mode 100644 index 00000000000..087f0220de5 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs @@ -0,0 +1,46 @@ +// { dg-output "104\n33\n1\n" } +#[rustc_builtin_macro] +macro_rules! include_bytes { + () => {{}}; +} + +extern "C" { + fn printf(s: *const i8, ...); +} + +fn print_int(value: i32) { + let s = "%d\n\0" as *const str as *const i8; + unsafe { + printf(s, value); + } +} + +fn main() -> i32 { + let bytes = include_bytes!("include.txt"); + + print_int(bytes[0] as i32); + print_int(bytes[14] as i32); + + let the_bytes = b"hello, include!\n"; + + let x = bytes[0] == the_bytes[0] + && bytes[1] == the_bytes[1] + && bytes[2] == the_bytes[2] + && bytes[3] == the_bytes[3] + && bytes[4] == the_bytes[4] + && bytes[5] == the_bytes[5] + && bytes[6] == the_bytes[6] + && bytes[7] == the_bytes[7] + && bytes[8] == the_bytes[8] + && bytes[9] == the_bytes[9] + && bytes[10] == the_bytes[10] + && bytes[11] == the_bytes[11] + && bytes[12] == the_bytes[12] + && bytes[13] == the_bytes[13] + && bytes[14] == the_bytes[14] + && bytes[15] == the_bytes[15]; + + print_int(x as i32); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs new file mode 100644 index 00000000000..6f9871d379c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs @@ -0,0 +1,27 @@ +// { dg-output "hello, include!\n" } +#[rustc_builtin_macro] +macro_rules! include_str { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: &str) { + unsafe { + printf( + "%s" as *const str as *const i8, + s as *const str as *const i8, + ); + } +} + +fn main() -> i32 { + // include_str! (and include_bytes!) allow for an optional trailing comma. + let my_str = include_str!("include.txt",); + + print(my_str); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_line.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_line.rs new file mode 100644 index 00000000000..02541ed52e2 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_macro_line.rs @@ -0,0 +1,25 @@ +// { dg-output "18\n21\n" } +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: u32) { + unsafe { + printf("%u\n\0" as *const str as *const i8, s); + } +} + +#[rustc_builtin_macro] +macro_rules! line { + () => {{}}; +} + +fn main() -> i32 { + let a = line!(); + print(a); + + let b = line!(); + print(b); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_macros1.rs b/gcc/testsuite/rust/execute/torture/builtin_macros1.rs new file mode 100644 index 00000000000..5976478e426 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_macros1.rs @@ -0,0 +1,21 @@ +// { dg-output "rust/execute/torture/builtin_macros1.rs" } +#[rustc_builtin_macro] +macro_rules! file { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: &str) { + unsafe { + printf("%s\n\0" as *const str as *const i8, s); + } +} + +fn main() -> i32 { + print(file!()); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_macros3.rs b/gcc/testsuite/rust/execute/torture/builtin_macros3.rs new file mode 100644 index 00000000000..24555cbdb8a --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_macros3.rs @@ -0,0 +1,28 @@ +// { dg-output "14\n42\n" } +#[rustc_builtin_macro] +macro_rules! column { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: u32) { + unsafe { + printf("%u\n\0" as *const str as *const i8, s); + } +} + +fn main() -> i32 { + let c0 = column!(); + + print(c0); + + let c1 = column!(); + + print(c1); + + 0 +} + diff --git a/gcc/testsuite/rust/execute/torture/cfg1.rs b/gcc/testsuite/rust/execute/torture/cfg1.rs new file mode 100644 index 00000000000..d3c56295503 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/cfg1.rs @@ -0,0 +1,32 @@ +// { dg-additional-options "-w -frust-cfg=A" } +// { dg-output "test1\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[cfg(A)] +fn test() { + unsafe { + let a = "test1\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } +} + +#[cfg(B)] +fn test() { + unsafe { + let a = "test2\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } +} + +fn main() -> i32 { + test(); + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/cfg2.rs b/gcc/testsuite/rust/execute/torture/cfg2.rs new file mode 100644 index 00000000000..5048bcb2791 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/cfg2.rs @@ -0,0 +1,31 @@ +// { dg-additional-options "-w -frust-cfg=A" } +// { dg-output "test1\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn test() { + #[cfg(A)] + unsafe { + let a = "test1\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + #[cfg(B)] + unsafe { + let a = "test2\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } +} + +fn main() -> i32 { + test(); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/cfg3.rs b/gcc/testsuite/rust/execute/torture/cfg3.rs new file mode 100644 index 00000000000..89312344b23 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/cfg3.rs @@ -0,0 +1,37 @@ +// { dg-additional-options "-w -frust-cfg=A" } +// { dg-output "test1\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(i32); +impl Foo { + #[cfg(A)] + fn test(&self) { + unsafe { + let a = "test1\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } + + #[cfg(B)] + fn test(&self) { + unsafe { + let a = "test2\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } +} + +fn main() -> i32 { + let a = Foo(123); + a.test(); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/cfg4.rs b/gcc/testsuite/rust/execute/torture/cfg4.rs new file mode 100644 index 00000000000..d1c2a22a0ff --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/cfg4.rs @@ -0,0 +1,38 @@ +// { dg-additional-options "-w -frust-cfg=A" } +// { dg-output "test1\ntest2\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(i32); +impl Foo { + #[cfg(A)] + fn test(&self) { + unsafe { + let a = "test1\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } + + #[cfg(not(B))] + fn test2(&self) { + unsafe { + let a = "test2\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } +} + +fn main() -> i32 { + let a = Foo(123); + a.test(); + a.test2(); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/cfg5.rs b/gcc/testsuite/rust/execute/torture/cfg5.rs new file mode 100644 index 00000000000..581a29bb89d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/cfg5.rs @@ -0,0 +1,13 @@ +// { dg-additional-options "-w -frust-cfg=A" } + +fn main() -> i32 { + let mut a = 0; + + #[cfg(A)] + a = 3; + + #[cfg(B)] + a = 40; + + a - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/coercion1.rs b/gcc/testsuite/rust/execute/torture/coercion1.rs new file mode 100644 index 00000000000..2cdb9bbca38 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/coercion1.rs @@ -0,0 +1,41 @@ +/* { dg-output "123\n123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(i32); +trait Bar { + fn baz(&self); +} + +impl Bar for Foo { + fn baz(&self) { + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, self.0); + } + } +} + +fn static_dispatch(t: &T) { + t.baz(); +} + +fn dynamic_dispatch(t: &dyn Bar) { + t.baz(); +} + +fn main() -> i32 { + let a; + a = Foo(123); + static_dispatch(&a); + + let b: &dyn Bar; + b = &a; + dynamic_dispatch(b); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/coercion2.rs b/gcc/testsuite/rust/execute/torture/coercion2.rs new file mode 100644 index 00000000000..12dd68ff5f7 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/coercion2.rs @@ -0,0 +1,39 @@ +/* { dg-output "123\n123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(i32); +trait Bar { + fn baz(&self); +} + +impl Bar for Foo { + fn baz(&self) { + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, self.0); + } + } +} + +fn static_dispatch(t: &T) { + t.baz(); +} + +fn dynamic_dispatch(t: &dyn Bar) { + t.baz(); +} + +fn main() -> i32 { + let a; + a = &Foo(123); + + static_dispatch(a); + dynamic_dispatch(a); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/const_fold1.rs b/gcc/testsuite/rust/execute/torture/const_fold1.rs new file mode 100644 index 00000000000..3cd6c0c77b5 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const_fold1.rs @@ -0,0 +1,13 @@ +// { dg-additional-options "-w" } +const fn const_fn() -> usize { + 4 +} + +const FN_TEST: usize = const_fn(); + +const TEST: usize = 2 + FN_TEST; + +fn main() -> i32 { + let a: [_; 12] = [5; TEST * 2]; + a[6] - 5 +} diff --git a/gcc/testsuite/rust/execute/torture/const_fold2.rs b/gcc/testsuite/rust/execute/torture/const_fold2.rs new file mode 100644 index 00000000000..c525648fe0b --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const_fold2.rs @@ -0,0 +1,16 @@ +// { dg-additional-options "-w" } +const A: i32 = 1; +const B: i32 = { A + 2 }; + +const fn test() -> i32 { + B +} + +const C: i32 = { + const a: i32 = 4; + test() + a +}; + +fn main() -> i32 { + C - 7 +} diff --git a/gcc/testsuite/rust/execute/torture/copy_nonoverlapping1.rs b/gcc/testsuite/rust/execute/torture/copy_nonoverlapping1.rs new file mode 100644 index 00000000000..2ae7a0869e3 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/copy_nonoverlapping1.rs @@ -0,0 +1,17 @@ +extern "rust-intrinsic" { + pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +} + +fn main() -> i32 { + let i = 15; + let mut i_copy = 16; + + let i = &i as *const i32; + let i_copy = &mut i_copy as *mut i32; + + unsafe { + copy_nonoverlapping(i, i_copy, 1); + + *i_copy - *i + } +} \ No newline at end of file diff --git a/gcc/testsuite/rust/execute/torture/empty_main.rs b/gcc/testsuite/rust/execute/torture/empty_main.rs new file mode 100644 index 00000000000..6442e1e4e83 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/empty_main.rs @@ -0,0 +1,3 @@ +fn main() -> i32 { + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/execute.exp b/gcc/testsuite/rust/execute/torture/execute.exp new file mode 100644 index 00000000000..6dfb6d2b446 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/execute.exp @@ -0,0 +1,33 @@ +# Copyright (C) 2021-2022 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 +# . + +# Execute tests, torture testing. + +# Load support procs. +load_lib rust-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +set saved-dg-do-what-default ${dg-do-what-default} + +set dg-do-what-default "run" +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" "" +set dg-do-what-default ${saved-dg-do-what-default} + +# All done. +dg-finish diff --git a/gcc/testsuite/rust/execute/torture/exit_error.rs b/gcc/testsuite/rust/execute/torture/exit_error.rs new file mode 100644 index 00000000000..c3d0d9f2480 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/exit_error.rs @@ -0,0 +1,5 @@ +// { dg-xfail-run-if "" { *-*-* } } + +fn main() -> i32 { + 1 +} diff --git a/gcc/testsuite/rust/execute/torture/extern_mod4.rs b/gcc/testsuite/rust/execute/torture/extern_mod4.rs new file mode 100644 index 00000000000..99b6fb5c9ba --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/extern_mod4.rs @@ -0,0 +1,19 @@ +// { dg-additional-options "-w" } +// { dg-output "12" } +mod modules; + +extern "C" { + fn printf(s: *const i8, ...); +} + +fn main() -> i32 { + unsafe { + let fmt_s = "%d\n\0"; + let fmt_p = fmt_s as *const str; + let fmt_i8 = fmt_p as *const i8; + + printf(fmt_i8, modules::return_12()); + } + + return 0; +} diff --git a/gcc/testsuite/rust/execute/torture/func1.rs b/gcc/testsuite/rust/execute/torture/func1.rs new file mode 100644 index 00000000000..0a093d88587 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/func1.rs @@ -0,0 +1,5 @@ +fn main() -> i32 { + 1; + 2; + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/helloworld1.rs b/gcc/testsuite/rust/execute/torture/helloworld1.rs new file mode 100644 index 00000000000..d416efa33af --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/helloworld1.rs @@ -0,0 +1,15 @@ +/* { dg-output "Hello World" }*/ +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + unsafe { + let a = "Hello World"; + let b = a as *const str; + let c = b as *const i8; + + puts(c); + } + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/helloworld2.rs b/gcc/testsuite/rust/execute/torture/helloworld2.rs new file mode 100644 index 00000000000..cc05f3798fa --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/helloworld2.rs @@ -0,0 +1,15 @@ +/* { dg-output "Hello World 123\n" }*/ +extern "C" { + fn printf(s: *const i8, ...); +} + +fn main() -> i32 { + unsafe { + let a = "Hello World %i\n"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, 123); + } + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/include.txt b/gcc/testsuite/rust/execute/torture/include.txt new file mode 100644 index 00000000000..12c368778e1 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/include.txt @@ -0,0 +1 @@ +hello, include! diff --git a/gcc/testsuite/rust/execute/torture/index1.rs b/gcc/testsuite/rust/execute/torture/index1.rs new file mode 100644 index 00000000000..4682978bdd0 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/index1.rs @@ -0,0 +1,28 @@ +// { dg-additional-options "-w" } +#[lang = "index"] +trait Index { + type Output; + + fn index(&self, index: Idx) -> &Self::Output; +} + +struct Foo(i32, i32); +impl Index for Foo { + type Output = i32; + + fn index(&self, index: isize) -> &i32 { + if index == 0 { + &self.0 + } else { + &self.1 + } + } +} + +fn main() -> i32 { + let a = Foo(1, 2); + let b = a[0]; + let c = a[1]; + + c - b - 1 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1120.rs b/gcc/testsuite/rust/execute/torture/issue-1120.rs new file mode 100644 index 00000000000..242c94b5cb6 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1120.rs @@ -0,0 +1,123 @@ +// { dg-additional-options "-w" } +extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + pub fn offset(dst: *const T, offset: isize) -> *const T; +} + +struct FatPtr { + data: *const T, + len: usize, +} + +pub union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +pub enum Option { + None, + Some(T), +} + +#[lang = "Range"] +pub struct Range { + pub start: Idx, + pub end: Idx, +} + +#[lang = "const_slice_ptr"] +impl *const [T] { + pub const fn len(self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +#[lang = "const_ptr"] +impl *const T { + pub const unsafe fn offset(self, count: isize) -> *const T { + unsafe { offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { + unsafe { + Repr { + raw: FatPtr { data, len }, + } + .rust + } +} + +#[lang = "index"] +trait Index { + type Output; + + fn index(&self, index: Idx) -> &Self::Output; +} + +pub unsafe trait SliceIndex { + type Output; + + fn get(self, slice: &T) -> Option<&Self::Output>; + + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; + + fn index(self, slice: &T) -> &Self::Output; +} + +unsafe impl SliceIndex<[T]> for Range { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&[T]> { + if self.start > self.end + /* || self.end > slice.len() */ + { + Option::None + } else { + unsafe { Option::Some(&*self.get_unchecked(slice)) } + } + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + unsafe { + let a: *const T = slice.as_ptr(); + let b: *const T = a.add(self.start); + slice_from_raw_parts(b, self.end - self.start) + } + } + + fn index(self, slice: &[T]) -> &[T] { + unsafe { &*self.get_unchecked(slice) } + } +} + +impl Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +fn main() -> i32 { + let a = [1, 2, 3, 4, 5]; + let b = &a[1..3]; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1133.rs b/gcc/testsuite/rust/execute/torture/issue-1133.rs new file mode 100644 index 00000000000..f2080a6e072 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1133.rs @@ -0,0 +1,146 @@ +// { dg-additional-options "-w" } +extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + pub fn offset(dst: *const T, offset: isize) -> *const T; +} + +struct FatPtr { + data: *const T, + len: usize, +} + +pub union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +pub enum Option { + None, + Some(T), +} + +#[lang = "Range"] +pub struct Range { + pub start: Idx, + pub end: Idx, +} + +#[lang = "const_slice_ptr"] +impl *const [T] { + pub const fn len(self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +#[lang = "const_ptr"] +impl *const T { + pub const unsafe fn offset(self, count: isize) -> *const T { + unsafe { offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { + unsafe { + Repr { + raw: FatPtr { data, len }, + } + .rust + } +} + +#[lang = "index"] +trait Index { + type Output; + + fn index(&self, index: Idx) -> &Self::Output; +} + +pub unsafe trait SliceIndex { + type Output; + + fn get(self, slice: &T) -> Option<&Self::Output>; + + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; + + fn index(self, slice: &T) -> &Self::Output; +} + +unsafe impl SliceIndex<[T]> for usize { + type Output = T; + + fn get(self, slice: &[T]) -> Option<&T> { + unsafe { Option::Some(&*self.get_unchecked(slice)) } + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { slice.as_ptr().add(self) } + } + + fn index(self, slice: &[T]) -> &T { + // N.B., use intrinsic indexing + // &(*slice)[self] + unsafe { &*self.get_unchecked(slice) } + } +} + +unsafe impl SliceIndex<[T]> for Range { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&[T]> { + if self.start > self.end + /* || self.end > slice.len() */ + { + Option::None + } else { + unsafe { Option::Some(&*self.get_unchecked(slice)) } + } + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + unsafe { + let a: *const T = slice.as_ptr(); + let b: *const T = a.add(self.start); + slice_from_raw_parts(b, self.end - self.start) + } + } + + fn index(self, slice: &[T]) -> &[T] { + unsafe { &*self.get_unchecked(slice) } + } +} + +impl Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +fn main() -> i32 { + let a = [1, 2, 3, 4, 5]; + let b = &a[1..3]; + let c = b[1]; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1198.rs b/gcc/testsuite/rust/execute/torture/issue-1198.rs new file mode 100644 index 00000000000..fce44ad1994 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1198.rs @@ -0,0 +1,75 @@ +/* { dg-output "foo_deref\nimm_deref\n123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "imm_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +impl Deref for &mut T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +struct Foo(T); +impl Deref for Foo { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { + let a = "foo_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + &self.0 + } +} + +fn main() -> i32 { + let foo: Foo = Foo(123); + let bar: &i32 = &foo; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, *bar); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1231.rs b/gcc/testsuite/rust/execute/torture/issue-1231.rs new file mode 100644 index 00000000000..970e86f917a --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1231.rs @@ -0,0 +1,36 @@ +// { dg-additional-options "-w" } +// { dg-output "outer\ninner\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn machin() { + unsafe { + let a = "outer\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, 123); + } +} + +fn bidule() { + fn machin() { + unsafe { + let a = "inner\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, 123); + } + } + + self::machin(); + machin(); +} + +fn main() -> i32 { + bidule(); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1232.rs b/gcc/testsuite/rust/execute/torture/issue-1232.rs new file mode 100644 index 00000000000..c56d5c18695 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1232.rs @@ -0,0 +1,159 @@ +// { dg-additional-options "-w" } +// { dg-output "slice_access=3\n" } +extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + fn offset(dst: *const T, offset: isize) -> *const T; +} + +extern "C" { + fn printf(s: *const i8, ...); +} + +struct FatPtr { + data: *const T, + len: usize, +} + +pub union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +pub enum Option { + None, + Some(T), +} + +#[lang = "Range"] +pub struct Range { + pub start: Idx, + pub end: Idx, +} + +#[lang = "const_slice_ptr"] +impl *const [T] { + pub const fn len(self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +#[lang = "const_ptr"] +impl *const T { + pub const unsafe fn offset(self, count: isize) -> *const T { + unsafe { offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { + unsafe { + Repr { + raw: FatPtr { data, len }, + } + .rust + } +} + +#[lang = "index"] +trait Index { + type Output; + + fn index(&self, index: Idx) -> &Self::Output; +} + +pub unsafe trait SliceIndex { + type Output; + + fn get(self, slice: &T) -> Option<&Self::Output>; + + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; + + fn index(self, slice: &T) -> &Self::Output; +} + +unsafe impl SliceIndex<[T]> for usize { + type Output = T; + + fn get(self, slice: &[T]) -> Option<&T> { + unsafe { Option::Some(&*self.get_unchecked(slice)) } + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { slice.as_ptr().add(self) } + } + + fn index(self, slice: &[T]) -> &T { + // N.B., use intrinsic indexing + // &(*slice)[self] + unsafe { &*self.get_unchecked(slice) } + } +} + +unsafe impl SliceIndex<[T]> for Range { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&[T]> { + if self.start > self.end + /* || self.end > slice.len() */ + { + Option::None + } else { + unsafe { Option::Some(&*self.get_unchecked(slice)) } + } + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + unsafe { + let a: *const T = slice.as_ptr(); + let b: *const T = a.add(self.start); + slice_from_raw_parts(b, self.end - self.start) + } + } + + fn index(self, slice: &[T]) -> &[T] { + unsafe { &*self.get_unchecked(slice) } + } +} + +impl Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +fn main() -> i32 { + let array = [1, 2, 3, 4, 5]; + let slice = &array[1..3]; + let slice_access = slice[1]; + + unsafe { + let a = "slice_access=%i\n"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, slice_access); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1249.rs b/gcc/testsuite/rust/execute/torture/issue-1249.rs new file mode 100644 index 00000000000..072204ea877 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1249.rs @@ -0,0 +1,39 @@ +// { dg-options "-w" } +// { dg-output "1\n2\n" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +trait T { + fn foo(&self); +} + +impl dyn T { + fn bar(&self) { + unsafe { + let a = "1\n\0"; + let b = a as *const str; + let c = b as *const i8; + printf(c); + } + self.foo() + } +} + +struct S; +impl T for S { + fn foo(&self) { + unsafe { + let a = "2\n\0"; + let b = a as *const str; + let c = b as *const i8; + printf(c); + } + } +} + +pub fn main() -> i32 { + ::bar(&S); + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1436.rs b/gcc/testsuite/rust/execute/torture/issue-1436.rs new file mode 100644 index 00000000000..5c079a61f07 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1436.rs @@ -0,0 +1,172 @@ +// { dg-options "-w" } +// { dg-output "" } +mod intrinsics { + extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + pub fn offset(ptr: *const T, count: isize) -> *const T; + } +} + +mod mem { + extern "rust-intrinsic" { + fn size_of() -> usize; + } +} + +extern "C" { + fn printf(s: *const i8, ...); +} + +struct FatPtr { + data: *const T, + len: usize, +} + +pub union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +pub enum Option { + None, + Some(T), +} + +#[lang = "Range"] +pub struct Range { + pub start: Idx, + pub end: Idx, +} + +#[lang = "const_slice_ptr"] +impl *const [T] { + pub const fn len(self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +#[lang = "const_ptr"] +impl *const T { + pub const unsafe fn offset(self, count: isize) -> *const T { + unsafe { intrinsics::offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { + unsafe { + Repr { + raw: FatPtr { data, len }, + } + .rust + } +} + +#[lang = "index"] +trait Index { + type Output; + + fn index(&self, index: Idx) -> &Self::Output; +} + +impl [T] { + pub const fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub const fn len(&self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } +} + +pub unsafe trait SliceIndex { + type Output; + + fn get(self, slice: &T) -> Option<&Self::Output>; + + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; + + fn index(self, slice: &T) -> &Self::Output; +} + +unsafe impl SliceIndex<[T]> for usize { + type Output = T; + + fn get(self, slice: &[T]) -> Option<&T> { + unsafe { Option::Some(&*self.get_unchecked(slice)) } + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { slice.as_ptr().add(self) } + } + + fn index(self, slice: &[T]) -> &T { + unsafe { &*self.get_unchecked(slice) } + } +} + +unsafe impl SliceIndex<[T]> for Range { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&[T]> { + if self.start > self.end || self.end > slice.len() { + Option::None + } else { + unsafe { Option::Some(&*self.get_unchecked(slice)) } + } + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + unsafe { + let a: *const T = slice.as_ptr(); + let b: *const T = a.add(self.start); + slice_from_raw_parts(b, self.end - self.start) + } + } + + fn index(self, slice: &[T]) -> &[T] { + unsafe { &*self.get_unchecked(slice) } + } +} + +impl Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + fn index(&self, index: I) -> &I::Output { + unsafe { + let a = "slice-index\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + index.index(self) + } +} + +fn main() -> i32 { + let a = [1, 2, 3, 4, 5]; + let b = a[1]; + + b - 2 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1496.rs b/gcc/testsuite/rust/execute/torture/issue-1496.rs new file mode 100644 index 00000000000..9f08b2ae98a --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1496.rs @@ -0,0 +1,75 @@ +/* { dg-output "foo_deref\nimm_deref\n123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "imm_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +impl Deref for &mut T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +struct Foo(T); +impl Deref for Foo { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { + let a = "foo_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + &self.0 + } +} + +fn main() -> i32 { + let foo = Foo(123); + let bar = &foo as &i32; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, *bar); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-647.rs b/gcc/testsuite/rust/execute/torture/issue-647.rs new file mode 100644 index 00000000000..3f427ccb785 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-647.rs @@ -0,0 +1,33 @@ +/* { dg-output "Hello World 123\n" }*/ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(T); + +struct Bar { + a: Foo, + b: bool, + // { dg-warning "field is never read" "" { target *-*-* } .-1 } +} + +fn test(a: Bar) -> Foo { + a.a +} + +fn main() -> i32 { + let a: Bar = Bar:: { + a: Foo::(123), + b: true, + }; + let result: Foo = test(a); + + unsafe { + let a = "Hello World %i\n"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, result.0); + } + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-845.rs b/gcc/testsuite/rust/execute/torture/issue-845.rs new file mode 100644 index 00000000000..4c689e3b6c8 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-845.rs @@ -0,0 +1,47 @@ +// { dg-output "Foo::bar\n" } +// { dg-additional-options "-w" } +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo {} + +trait Bar { + fn bar(&self) { + unsafe { + let _a = "Bar::bar\n\0"; + let _b = _a as *const str; + let _c = _b as *const i8; + printf(_c); + } + } +} + +impl Foo { + fn bar(&self) { + unsafe { + let _a = "Foo::bar\n\0"; + let _b = _a as *const str; + let _c = _b as *const i8; + printf(_c); + } + } +} + +impl Bar for Foo { + fn bar(&self) { + unsafe { + let _a = "::bar\n\0"; + let _b = _a as *const str; + let _c = _b as *const i8; + printf(_c); + } + } +} + +pub fn main() -> i32 { + let mut f = Foo {}; + f.bar(); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-851.rs b/gcc/testsuite/rust/execute/torture/issue-851.rs new file mode 100644 index 00000000000..3881c7a2ada --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-851.rs @@ -0,0 +1,35 @@ +/* { dg-output "Result: 123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +enum Foo { + A, + B(T), +} + +fn inspect(a: Foo) { + match a { + Foo::A => unsafe { + let a = "A\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + }, + Foo::B(x) => unsafe { + let a = "Result: %i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, x); + }, + } +} + +fn main() -> i32 { + let a = Foo::B(123); + inspect(a); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-858.rs b/gcc/testsuite/rust/execute/torture/issue-858.rs new file mode 100644 index 00000000000..5a43f3e1b1a --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-858.rs @@ -0,0 +1,32 @@ +/* { dg-output "Result: 123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +enum Foo { + A, + B(T), +} + +fn main() -> i32 { + let result = Foo::B(123); + + match result { + Foo::A => unsafe { + let a = "A\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + }, + Foo::B(x) => unsafe { + let a = "Result: %i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, x); + }, + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-976.rs b/gcc/testsuite/rust/execute/torture/issue-976.rs new file mode 100644 index 00000000000..42cf596fb7d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-976.rs @@ -0,0 +1,14 @@ +/* { dg-output "hi" } */ +fn main() -> i32 { + { + extern "C" { + fn puts(s: *const i8); + } + + unsafe { + puts("hi\0" as *const str as *const i8); + } + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-995.rs b/gcc/testsuite/rust/execute/torture/issue-995.rs new file mode 100644 index 00000000000..42570e33f74 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-995.rs @@ -0,0 +1,9 @@ +struct Pattern(i32); + +fn pattern_as_arg(Pattern(value): Pattern) -> i32 { + value +} + +fn main() -> i32 { + pattern_as_arg(Pattern(15)) - 15 +} diff --git a/gcc/testsuite/rust/execute/torture/macros1.rs b/gcc/testsuite/rust/execute/torture/macros1.rs new file mode 100644 index 00000000000..652d2d8fe5b --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros1.rs @@ -0,0 +1,13 @@ +macro_rules! add { + ($a:expr,$b:expr) => { + $a + $b + }; +} + +fn test() -> i32 { + add!(1 + 2, 3) +} + +fn main() -> i32 { + test() - 6 +} diff --git a/gcc/testsuite/rust/execute/torture/macros10.rs b/gcc/testsuite/rust/execute/torture/macros10.rs new file mode 100644 index 00000000000..155a440ee04 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros10.rs @@ -0,0 +1,22 @@ +// { dg-output "18\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn print_int(value: i32) { + let s = "%d\n\0" as *const str as *const i8; + unsafe { + printf(s, value); + } +} + +macro_rules! add_exprs { + ($($e:expr)*) => (0 $(+ $e)*) +} + +fn main() -> i32 { + // 1 + 2 + 15 => 18 + print_int(add_exprs!(1 2 15)); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros11.rs b/gcc/testsuite/rust/execute/torture/macros11.rs new file mode 100644 index 00000000000..5bde97d3dd4 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros11.rs @@ -0,0 +1,25 @@ +// { dg-output "2" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn print_int(value: i32) { + let s = "%d\n\0"; + let s_p = s as *const str; + let c_p = s_p as *const i8; + unsafe { + printf(c_p, value); + } +} + +macro_rules! add_exprs { + ($($e:expr)?) => (0 $(+ $e)?) +} + +fn main() -> i32 { + // 2 + let a = add_exprs!(2); + print_int(a); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros12.rs b/gcc/testsuite/rust/execute/torture/macros12.rs new file mode 100644 index 00000000000..d310dff9ba8 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros12.rs @@ -0,0 +1,22 @@ +// { dg-output "0\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn print_int(value: i32) { + let s = "%d\n\0" as *const str as *const i8; + unsafe { + printf(s, value); + } +} + +macro_rules! add_exprs { + ($($e:expr)?) => (0 $(+ $e)?) +} + +fn main() -> i32 { + // 0 + print_int(add_exprs!()); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros13.rs b/gcc/testsuite/rust/execute/torture/macros13.rs new file mode 100644 index 00000000000..afb20264625 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros13.rs @@ -0,0 +1,22 @@ +// { dg-output "18\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn print_int(value: i32) { + let s = "%d\n\0" as *const str as *const i8; + unsafe { + printf(s, value); + } +} + +macro_rules! add_exprs { + ($($e:expr)+) => (0 $(+ $e)+) +} + +fn main() -> i32 { + // 1 + 2 + 15 => 18 + print_int(add_exprs!(1 2 15)); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros14.rs b/gcc/testsuite/rust/execute/torture/macros14.rs new file mode 100644 index 00000000000..00656546d4c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros14.rs @@ -0,0 +1,22 @@ +// { dg-output "15\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn print_int(value: i32) { + let s = "%d\n\0" as *const str as *const i8; + unsafe { + printf(s, value); + } +} + +macro_rules! add_exprs { + ($($e:expr)*) => (15 $(+ $e)*) +} + +fn main() -> i32 { + // 15 + print_int(add_exprs!()); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros16.rs b/gcc/testsuite/rust/execute/torture/macros16.rs new file mode 100644 index 00000000000..47ab2411c0d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros16.rs @@ -0,0 +1,14 @@ +macro_rules! add { + ($e:literal) => { + 0 + $e + }; + ($e:literal $($es:literal)*) => { + $e + add!($($es)*) + }; +} + +fn main() -> i32 { + let a = add!(1 2 3 10); // 16 + + a - 16 +} diff --git a/gcc/testsuite/rust/execute/torture/macros17.rs b/gcc/testsuite/rust/execute/torture/macros17.rs new file mode 100644 index 00000000000..390352ec47f --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros17.rs @@ -0,0 +1,17 @@ +macro_rules! two { + (2) => { + 3 + }; +} + +macro_rules! one { + (1) => {{ + two!(2) + }}; +} + +fn main() -> i32 { + let a = one!(1); + + a - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/macros18.rs b/gcc/testsuite/rust/execute/torture/macros18.rs new file mode 100644 index 00000000000..61df17e9da5 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros18.rs @@ -0,0 +1,14 @@ +macro_rules! add { + ($e:literal) => { + 0 + $e + }; + ($e:literal $($es:literal)*) => { + $e + add!($($es)*) + }; +} + +fn main() -> i32 { + let a = add!(3 4); // 7 + + a - 7 +} diff --git a/gcc/testsuite/rust/execute/torture/macros19.rs b/gcc/testsuite/rust/execute/torture/macros19.rs new file mode 100644 index 00000000000..4732545410e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros19.rs @@ -0,0 +1,14 @@ +macro_rules! add { + ($e:expr, $($es:expr),*) => { + $e + add!($($es),*) + }; + ($e:expr) => { + $e + }; +} + +fn main() -> i32 { + let a = add!(15, 2, 9); // 26 + + a - 26 +} diff --git a/gcc/testsuite/rust/execute/torture/macros2.rs b/gcc/testsuite/rust/execute/torture/macros2.rs new file mode 100644 index 00000000000..ba5098710ea --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros2.rs @@ -0,0 +1,40 @@ +// { dg-output "arg\narg\narg\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn f() { + unsafe { + let r_s = "arg\n\0"; + let s_p = r_s as *const str; + let c_p = s_p as *const i8; + + printf(c_p); + } +} + +macro_rules! kw0 { + (keyword) => { + f(); + }; +} + +macro_rules! kw1 { + (fn) => { + f(); + }; +} + +macro_rules! kw2 { + (kw0 kw1 kw3) => { + f(); + }; +} + +fn main() -> i32 { + kw0!(keyword); + kw1!(fn); + kw2!(kw0 kw1 kw3); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros20.rs b/gcc/testsuite/rust/execute/torture/macros20.rs new file mode 100644 index 00000000000..97317a0879e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros20.rs @@ -0,0 +1,14 @@ +macro_rules! add { + ($e:expr , $($es:expr) , *) => { + $e + add!($($es) , *) + }; + ($e:expr) => { + $e + }; +} + +fn main() -> i32 { + let a = add!(15, 2, 9); // 26 + + a - 26 +} diff --git a/gcc/testsuite/rust/execute/torture/macros21.rs b/gcc/testsuite/rust/execute/torture/macros21.rs new file mode 100644 index 00000000000..2508be1a6fd --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros21.rs @@ -0,0 +1,15 @@ +macro_rules! add_parens { + ($($rep:ident ( ) )*) => { + { 0 $(+ $rep ( ))* } + }; +} + +fn f() -> i32 { + 1 +} + +fn main() -> i32 { + let a = add_parens!(f() f() f()); + + a - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/macros22.rs b/gcc/testsuite/rust/execute/torture/macros22.rs new file mode 100644 index 00000000000..3f291ace98e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros22.rs @@ -0,0 +1,27 @@ +// { dg-output "1\n2\nNaN\n3\n" } + +macro_rules! print_num { + ($l:literal) => {{ + unsafe { + printf("%d\n\0" as *const str as *const i8, $l); + } + }}; +} + +extern "C" { + fn printf(s: *const i8, ...); +} + +// Check to make sure that expanding macros does not break the flow of calls +fn main() -> i32 { + print_num!(1); + print_num!(2); + + unsafe { + printf("NaN\n\0" as *const str as *const i8); + } + + print_num!(3); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros23.rs b/gcc/testsuite/rust/execute/torture/macros23.rs new file mode 100644 index 00000000000..846352d0487 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros23.rs @@ -0,0 +1,19 @@ +trait Valuable { + const VALUE: i32; +} + +struct Something; + +macro_rules! implement { + () => { + const VALUE: i32 = 18; + }; +} + +impl Valuable for Something { + implement!(); +} + +fn main() -> i32 { + Something::VALUE - 18 +} diff --git a/gcc/testsuite/rust/execute/torture/macros24.rs b/gcc/testsuite/rust/execute/torture/macros24.rs new file mode 100644 index 00000000000..f838a83af66 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros24.rs @@ -0,0 +1,9 @@ +macro_rules! repeat { + ( $( $i:literal ),* ; $( $j:literal ),* ) => (( $( ($i,$j) ),* )) +} + +fn main() -> i32 { + let t = repeat!(1, 1; 2, 2); + + t.0 .0 + t.0 .1 + t.1 .0 + t.1 .1 - 6 +} diff --git a/gcc/testsuite/rust/execute/torture/macros25.rs b/gcc/testsuite/rust/execute/torture/macros25.rs new file mode 100644 index 00000000000..c2658721bdf --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros25.rs @@ -0,0 +1,13 @@ +macro_rules! t { + ($t:tt) => { + $t + }; +} + +fn frob() -> i32 { + t!(15) + t!((14)) +} + +fn main() -> i32 { + frob() - 29 +} diff --git a/gcc/testsuite/rust/execute/torture/macros26.rs b/gcc/testsuite/rust/execute/torture/macros26.rs new file mode 100644 index 00000000000..30f0beef0d9 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros26.rs @@ -0,0 +1,12 @@ +macro_rules! count_tt { + ($t:tt) => { 1 }; + ($t:tt $($ts:tt)*) => { 1 + count_tt!($($ts)*) }; +} + +fn main() -> i32 { + let count = count_tt!(1 2 let a = 15) + count_tt!(1 2 (let a = 15)); + // ^ ^ ^^^ ^ ^ ^^ ^ ^ ^^^^^^^^^^^^ + // 6 token-trees 3 token-trees + + count - 9 +} diff --git a/gcc/testsuite/rust/execute/torture/macros27.rs b/gcc/testsuite/rust/execute/torture/macros27.rs new file mode 100644 index 00000000000..d515bb278a0 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros27.rs @@ -0,0 +1,24 @@ +// { dg-additional-options "-frust-cfg=A" } + +macro_rules! attr { + (#[$attr:meta] $s:stmt) => { + #[$attr] + $s; + }; +} + +fn main() -> i32 { + let mut a = 0; + + attr! { + #[cfg(A)] + a = 3 + }; + + attr! { + #[cfg(B)] + a = 40 + }; + + a - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/macros28.rs b/gcc/testsuite/rust/execute/torture/macros28.rs new file mode 100644 index 00000000000..b011f924149 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros28.rs @@ -0,0 +1,13 @@ +macro_rules! t { + () => { + i32 + }; +} + +fn id(arg: T) -> T { + arg +} + +fn main() -> i32 { + id::(15) - 15 +} diff --git a/gcc/testsuite/rust/execute/torture/macros29.rs b/gcc/testsuite/rust/execute/torture/macros29.rs new file mode 100644 index 00000000000..306979b9b5b --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros29.rs @@ -0,0 +1,24 @@ +// { dg-output "1\n" } +#[rustc_builtin_macro] +macro_rules! concat { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: u32) { + unsafe { + printf("%u\n\0" as *const str as *const i8, s); + } +} + +fn main() -> i32 { + let res = concat!("test2") == "test3"; + if !res { + print(1); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros3.rs b/gcc/testsuite/rust/execute/torture/macros3.rs new file mode 100644 index 00000000000..00f6d253f50 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros3.rs @@ -0,0 +1,61 @@ +// { dg-output "invok\ninvok\ninvok\ninvok\ninvok\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn f() { + unsafe { + let r_s = "invok\n\0"; + let s_p = r_s as *const str; + let c_p = s_p as *const i8; + + printf(c_p); + } +} + +macro_rules! invocation0 { + (valid) => { + f(); + }; + () => {}; +} + +macro_rules! invocation1 { + (valid) => {}; + () => { + f(); + }; +} + +macro_rules! invocation2 { + (valid) => { + f(); + }; + (invalid) => {}; +} + +macro_rules! invocation3 { + (this is a valid invocation) => { + f(); + }; + (not this one) => {}; +} + +macro_rules! invocation4 { + (fn f() {}) => { + f(); + }; + (not a keyword) => {}; +} + +fn main() -> i32 { + invocation0!(valid); + invocation1!(); + invocation2!(valid); + invocation3!(this is a valid invocation); + invocation4!( + fn f() {} + ); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros30.rs b/gcc/testsuite/rust/execute/torture/macros30.rs new file mode 100644 index 00000000000..ab36f5e78af --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros30.rs @@ -0,0 +1,25 @@ +// { dg-output "1\n" } +#[rustc_builtin_macro] +macro_rules! concat { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: u32) { + unsafe { + printf("%u\n\0" as *const str as *const i8, s); + } +} + +fn main() -> i32 { + let mut x = concat!("x"); + x = concat!("y"); + if x == "y" { + print(1); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros31.rs b/gcc/testsuite/rust/execute/torture/macros31.rs new file mode 100644 index 00000000000..483f897a92b --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros31.rs @@ -0,0 +1,32 @@ +// { dg-additional-options "-w -frust-cfg=A" } +// { dg-output "A\nB\n" } +#[rustc_builtin_macro] +macro_rules! cfg { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: &str) { + unsafe { + printf( + "%s\n" as *const str as *const i8, + s as *const str as *const i8, + ); + } +} + +fn main() -> i32 { + let cfg = cfg!(A) || cfg!(B); + if cfg { + print("A"); + } + let cfg = cfg!(A) && cfg!(B); + if !cfg { + print("B"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros4.rs b/gcc/testsuite/rust/execute/torture/macros4.rs new file mode 100644 index 00000000000..3303bfa58aa --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros4.rs @@ -0,0 +1,15 @@ +macro_rules! add { + ($a:expr,$b:expr) => { + $a + $b + }; + ($a:expr) => { + $a + }; +} + +fn main() -> i32 { + let mut x = add!(1); + x += add!(2, 3); + + x - 6 +} diff --git a/gcc/testsuite/rust/execute/torture/macros5.rs b/gcc/testsuite/rust/execute/torture/macros5.rs new file mode 100644 index 00000000000..822665494a4 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros5.rs @@ -0,0 +1,13 @@ +macro_rules! add { + ($a:expr,$b:expr) => {{ + $a + $b + }}; +} + +fn test() -> i32 { + add!(1, 2) +} + +fn main() -> i32 { + test() - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/macros6.rs b/gcc/testsuite/rust/execute/torture/macros6.rs new file mode 100644 index 00000000000..652a765d5a8 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros6.rs @@ -0,0 +1,12 @@ +macro_rules! Test { + ($a:ident, $b:ty) => { + struct $a($b); + }; +} + +Test!(Foo, i32); + +fn main() -> i32 { + let a = Foo(123); + a.0 - 123 +} diff --git a/gcc/testsuite/rust/execute/torture/macros7.rs b/gcc/testsuite/rust/execute/torture/macros7.rs new file mode 100644 index 00000000000..ed1f922f581 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros7.rs @@ -0,0 +1,28 @@ +// { dg-output "any\nany\nany\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn f() { + let r_s = "any\n\0"; + let s_p = r_s as *const str; + let c_p = s_p as *const i8; + + unsafe { + printf(c_p); + } +} + +macro_rules! any { + ($($a:expr)*) => { + f(); + }; +} + +fn main() -> i32 { + any!(); + any!(a + b); + any!(a + b 14 "gcc"); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros8.rs b/gcc/testsuite/rust/execute/torture/macros8.rs new file mode 100644 index 00000000000..a12aca4910e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros8.rs @@ -0,0 +1,27 @@ +// { dg-output "zo1\nzo1\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn f() { + let r_s = "zo1\n\0"; + let s_p = r_s as *const str; + let c_p = s_p as *const i8; + + unsafe { + printf(c_p); + } +} + +macro_rules! zero_or_one { + ($($a:expr)?) => { + f(); + }; +} + +fn main() -> i32 { + zero_or_one!(); + zero_or_one!(f()); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/macros9.rs b/gcc/testsuite/rust/execute/torture/macros9.rs new file mode 100644 index 00000000000..0e3fd24e8a9 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros9.rs @@ -0,0 +1,28 @@ +// { dg-output "oom\noom\noom\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn f() { + let r_s = "oom\n\0"; + let s_p = r_s as *const str; + let c_p = s_p as *const i8; + + unsafe { + printf(c_p); + } +} + +macro_rules! one_or_more { + ($($a:expr)+) => { + f(); + }; +} + +fn main() -> i32 { + one_or_more!(f()); + one_or_more!(f() f()); + one_or_more!(f() f() 15 + 12); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match1.rs b/gcc/testsuite/rust/execute/torture/match1.rs new file mode 100644 index 00000000000..e5af512f15d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match1.rs @@ -0,0 +1,58 @@ +// { dg-output "Foo::A\nFoo::B\nFoo::C x\nFoo::D 20 80\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +enum Foo { + A, + B, + C(char), + D { x: i32, y: i32 }, +} + +fn inspect(f: Foo) { + match f { + Foo::A => unsafe { + let a = "Foo::A\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + }, + Foo::B => unsafe { + let a = "Foo::B\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + }, + Foo::C(x) => unsafe { + let a = "Foo::C %c\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, x); + }, + Foo::D { x, y } => unsafe { + let a = "Foo::D %i %i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, x, y); + }, + } +} + +fn main() -> i32 { + let a = Foo::A; + let b = Foo::B; + let c = Foo::C('x'); + let d = Foo::D { x: 20, y: 80 }; + + inspect(a); + inspect(b); + inspect(c); + inspect(d); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match2.rs b/gcc/testsuite/rust/execute/torture/match2.rs new file mode 100644 index 00000000000..02cedf29b3c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match2.rs @@ -0,0 +1,41 @@ +// { dg-output "123\n80\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +enum Foo { + C(i32), + D { x: i32, y: i32 }, +} + +fn inspect(f: Foo) -> i32 { + match f { + Foo::C(x) => x, + Foo::D { x, y } => y, + } +} + +fn main() -> i32 { + let a = Foo::C(123); + let b = Foo::D { x: 20, y: 80 }; + + let result = inspect(a); + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, result); + } + + let result = inspect(b); + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, result); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match3.rs b/gcc/testsuite/rust/execute/torture/match3.rs new file mode 100644 index 00000000000..8cded3044df --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match3.rs @@ -0,0 +1,51 @@ +// { dg-output "Foo::A\nwildcard\nwildcard\nFoo::D 20 80\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +enum Foo { + A, + B, + C(char), + D { x: i32, y: i32 }, +} + +fn inspect(f: Foo) { + match f { + Foo::A => unsafe { + let a = "Foo::A\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + }, + Foo::D { x, y } => unsafe { + let a = "Foo::D %i %i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, x, y); + }, + _ => unsafe { + let a = "wildcard\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + }, + } +} + +fn main() -> i32 { + let a = Foo::A; + let b = Foo::B; + let c = Foo::C('x'); + let d = Foo::D { x: 20, y: 80 }; + + inspect(a); + inspect(b); + inspect(c); + inspect(d); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match_bool1.rs b/gcc/testsuite/rust/execute/torture/match_bool1.rs new file mode 100644 index 00000000000..101dbb58571 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match_bool1.rs @@ -0,0 +1,49 @@ +// { dg-output "182 is more than 100\n55 is less than 100\n" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +fn foo(x: bool) -> i32 { + match x { + true => { + return 182; + } + false => { + return 55; + } + } +} + +fn bar(y: i32) { + match y < 100 { + true => { + let a = "%i is less than 100\n\0"; + let b = a as *const str; + let c = b as *const i8; + + unsafe { + printf(c, y); + } + } + _ => { + let a = "%i is more than 100\n\0"; + let b = a as *const str; + let c = b as *const i8; + + unsafe { + printf(c, y); + } + } + } +} + +fn main() -> i32 { + let a = foo(true); + let b = foo(false); + + bar(a); + bar(b); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match_byte1.rs b/gcc/testsuite/rust/execute/torture/match_byte1.rs new file mode 100644 index 00000000000..3546cfb9d8b --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match_byte1.rs @@ -0,0 +1,56 @@ +// { dg-output "a\nseven\nquote\nelse" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +fn foo(x: u8) { + match x { + b'a' => { + let a = "a\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + b'\x07' => { + let a = "seven\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + b'\'' => { + let a = "quote\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + _ => { + let a = "else\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + } +} + +fn main() -> i32 { + let x: u8 = 7; + + foo(b'a'); + foo(x); + foo(b'\''); + foo(b'\\'); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match_char1.rs b/gcc/testsuite/rust/execute/torture/match_char1.rs new file mode 100644 index 00000000000..fa65876a907 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match_char1.rs @@ -0,0 +1,56 @@ +// { dg-output "amazing\nwildcard\ncompiler\nproductivity\n" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +fn foo(x: char) { + match x { + 'a' => { + let a = "amazing\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + 'c' => { + let a = "compiler\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + 'p' => { + let a = "productivity\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + _ => { + let a = "wildcard\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + } +} + +fn main() -> i32 { + let p = 'p'; + + foo('a'); + foo('b'); + foo('c'); + foo(p); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match_int1.rs b/gcc/testsuite/rust/execute/torture/match_int1.rs new file mode 100644 index 00000000000..209429added --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match_int1.rs @@ -0,0 +1,109 @@ +// { dg-output "other!\nother!\nother!\nfifteen!\nfifteen!\nother!\nother!\nfifteen!\n" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +fn foo_i32(x: i32) { + match x { + 15 => { + let a = "fifteen!\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + _ => { + let a = "other!\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + } +} + +fn foo_isize(x: isize) { + match x { + 15 => { + let a = "fifteen!\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + _ => { + let a = "other!\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + } +} + +fn foo_u32(x: u32) { + match x { + 15 => { + let a = "fifteen!\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + _ => { + let a = "other!\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + } +} + +fn foo_usize(x: usize) { + match x { + 15 => { + let a = "fifteen!\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + _ => { + let a = "other!\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + } +} + +fn main() -> i32 { + let x = -2; + foo_i32(x); + foo_i32(334); + foo_isize(-4768); + foo_isize(15); + + let y = 127; + foo_u32(15); + foo_u32(y); + foo_usize(2394); + foo_usize(15); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match_loop1.rs b/gcc/testsuite/rust/execute/torture/match_loop1.rs new file mode 100644 index 00000000000..bb6aee946f6 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match_loop1.rs @@ -0,0 +1,56 @@ +// { dg-output "E::One\nE::Two\nbreak!\n" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +enum E { + One, + Two, + Other, +} + +fn foo() { + let mut x = E::One; + + loop { + match x { + E::One => { + let a = "E::One\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + + x = E::Two; + } + E::Two => { + let a = "E::Two\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + + x = E::Other; + } + _ => { + let a = "break!\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + + break; + } + } + } +} + +fn main() -> i32 { + foo(); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match_range1.rs b/gcc/testsuite/rust/execute/torture/match_range1.rs new file mode 100644 index 00000000000..82e9e34a989 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match_range1.rs @@ -0,0 +1,37 @@ +// { dg-output "zero to END_RANGE\nzero to END_RANGE\nelse\n" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +const END_RANGE: i32 = 15; + +fn foo(x: i32) { + match x { + 0..=END_RANGE => { + let a = "zero to END_RANGE\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + + _ => { + let a = "else\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + } +} + +fn main() -> i32 { + foo(11); + foo(15); + foo(21); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match_range2.rs b/gcc/testsuite/rust/execute/torture/match_range2.rs new file mode 100644 index 00000000000..8153f9e1c7e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match_range2.rs @@ -0,0 +1,45 @@ +// { dg-output "lowercase\nuppercase\nother\n" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +const BIG_A: char = 'A'; +const BIG_Z: char = 'Z'; + +fn bar(x: char) { + match x { + 'a'..='z' => { + let a = "lowercase\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + BIG_A..=BIG_Z => { + let a = "uppercase\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + _ => { + let a = "other\n\0"; + let b = a as *const str; + let c = b as *const i8; + unsafe { + printf(c); + } + } + } +} + +fn main() -> i32 { + bar('b'); + bar('X'); + bar('!'); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match_tuple1.rs b/gcc/testsuite/rust/execute/torture/match_tuple1.rs new file mode 100644 index 00000000000..cb61cc0847c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match_tuple1.rs @@ -0,0 +1,45 @@ +// { dg-output "x:15\ny:20\n" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +enum Foo { + A, + B, +} + +fn inspect(f: Foo, g: u8) -> i32 { + match (f, g) { + (Foo::A, 1) => { + return 5; + } + + (Foo::A, 2) => { + return 10; + } + + (Foo::B, 2) => { + return 15; + } + + _ => { + return 20; + } + } + return 25; +} + +fn main() -> i32 { + let x = inspect(Foo::B, 2); + let y = inspect(Foo::B, 1); + + unsafe { + printf("x:%d\n" as *const str as *const i8, x); + } + unsafe { + printf("y:%d\n" as *const str as *const i8, y); + } + + y - x - 5 +} diff --git a/gcc/testsuite/rust/execute/torture/method1.rs b/gcc/testsuite/rust/execute/torture/method1.rs new file mode 100644 index 00000000000..6af6133939b --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/method1.rs @@ -0,0 +1,27 @@ +/* { dg-output "124\n458" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(i32); +impl Foo { + fn bar(&self, i: i32) { + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, self.0 + i); + } + } +} + +fn main() -> i32 { + let a = Foo(123); + a.bar(1); + + let b = &Foo(456); + b.bar(2); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/method2.rs b/gcc/testsuite/rust/execute/torture/method2.rs new file mode 100644 index 00000000000..f532b4488c6 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/method2.rs @@ -0,0 +1,76 @@ +// { dg-additional-options "-w" } +// { dg-output "foo_deref\nimm_deref\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "imm_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +impl Deref for &mut T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +struct Bar(i32); +impl Bar { + fn foobar(self) -> i32 { + self.0 + } +} + +struct Foo(T); +impl Deref for Foo { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { + let a = "foo_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + &self.0 + } +} + +pub fn main() -> i32 { + let bar = Bar(123); + let foo: Foo<&Bar> = Foo(&bar); + let foobar: i32 = foo.foobar(); + + foobar - 123 +} diff --git a/gcc/testsuite/rust/execute/torture/method3.rs b/gcc/testsuite/rust/execute/torture/method3.rs new file mode 100644 index 00000000000..0e9e8ff42a0 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/method3.rs @@ -0,0 +1,78 @@ +// { dg-additional-options "-w" } +// { dg-output "mut_deref\nfoobar: 123\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +#[lang = "deref_mut"] +pub trait DerefMut: Deref { + fn deref_mut(&mut self) -> &mut Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + +impl Deref for &mut T { + type Target = T; + fn deref(&self) -> &T { + *self + } +} + +pub struct Bar(i32); +impl Bar { + pub fn foobar(&mut self) -> i32 { + self.0 + } +} + +pub struct Foo(T); +impl Deref for Foo { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + &mut self.0 + } +} + +pub fn main() -> i32 { + let bar = Bar(123); + let mut foo: Foo = Foo(bar); + let foobar = foo.foobar(); + + unsafe { + let a = "foobar: %i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, foobar); + } + + foobar - 123 +} diff --git a/gcc/testsuite/rust/execute/torture/method4.rs b/gcc/testsuite/rust/execute/torture/method4.rs new file mode 100644 index 00000000000..5c6fdfe02c3 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/method4.rs @@ -0,0 +1,78 @@ +// { dg-additional-options "-w" } +// { dg-output "mut_deref\nfoobar: 123\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +#[lang = "deref_mut"] +pub trait DerefMut: Deref { + fn deref_mut(&mut self) -> &mut Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + +impl Deref for &mut T { + type Target = T; + fn deref(&self) -> &T { + *self + } +} + +pub struct Bar(i32); +impl Bar { + pub fn foobar(&mut self) -> i32 { + self.0 + } +} + +pub struct Foo(T); +impl Deref for Foo { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + &mut self.0 + } +} + +pub fn main() -> i32 { + let mut bar = Bar(123); + let mut foo: Foo<&mut Bar> = Foo(&mut bar); + let foobar = foo.foobar(); + + unsafe { + let a = "foobar: %i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, foobar); + } + + foobar - 123 +} diff --git a/gcc/testsuite/rust/execute/torture/mod1.rs b/gcc/testsuite/rust/execute/torture/mod1.rs new file mode 100644 index 00000000000..700393850af --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/mod1.rs @@ -0,0 +1,21 @@ +mod A { + pub mod B { + pub mod C { + pub struct Foo { + pub f: i32, + } + impl Foo { + pub fn new() -> Self { + Foo { f: 23i32 } + } + } + } + } +} + +fn main() -> i32 { + let a = A::B::C::Foo::new(); + let b = A::B::C::Foo { f: -23i32 }; + + a.f + b.f +} diff --git a/gcc/testsuite/rust/execute/torture/modules/mod.rs b/gcc/testsuite/rust/execute/torture/modules/mod.rs new file mode 100644 index 00000000000..9020aaf4bb8 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/modules/mod.rs @@ -0,0 +1,3 @@ +fn return_12() -> i32 { + 12 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_1.rs b/gcc/testsuite/rust/execute/torture/operator_overload_1.rs new file mode 100644 index 00000000000..5a28c5f4e93 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_1.rs @@ -0,0 +1,36 @@ +/* { dg-output "3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "add"] +pub trait Add { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; +} + +impl Add for i32 { + type Output = i32; + + fn add(self, other: i32) -> i32 { + let res = self + other; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res); + } + + res + } +} + +fn main() -> i32 { + let a; + a = 1 + 2; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_10.rs b/gcc/testsuite/rust/execute/torture/operator_overload_10.rs new file mode 100644 index 00000000000..f5d45db5338 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_10.rs @@ -0,0 +1,75 @@ +/* { dg-output "foo_deref\n123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "imm_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +impl Deref for &mut T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +struct Foo(T); +impl Deref for Foo { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { + let a = "foo_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + &self.0 + } +} + +fn main() -> i32 { + let foo: Foo = Foo(123); + let bar: i32 = *foo; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, bar); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_11.rs b/gcc/testsuite/rust/execute/torture/operator_overload_11.rs new file mode 100644 index 00000000000..1919941c486 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_11.rs @@ -0,0 +1,37 @@ +// { dg-output "1\n" } +// { dg-additional-options "-w" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "bitand"] +pub trait BitAnd { + type Output; + + fn bitand(self, rhs: Rhs) -> Self::Output; +} + +impl BitAnd for i32 { + type Output = i32; + + fn bitand(self, other: i32) -> i32 { + let res = self & other; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res); + } + + res + } +} + +fn main() -> i32 { + let a; + a = 1 & 1; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_12.rs b/gcc/testsuite/rust/execute/torture/operator_overload_12.rs new file mode 100644 index 00000000000..7433330fa31 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_12.rs @@ -0,0 +1,31 @@ +// { dg-output "1\n" } +// { dg-additional-options "-w" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "bitand_assign"] +pub trait BitAndAssign { + fn bitand_assign(&mut self, rhs: Rhs); +} + +impl BitAndAssign for i32 { + fn bitand_assign(&mut self, other: i32) { + *self &= other; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, *self); + } + } +} + +fn main() -> i32 { + let mut a = 1; + a &= 1; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_2.rs b/gcc/testsuite/rust/execute/torture/operator_overload_2.rs new file mode 100644 index 00000000000..a577718451d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_2.rs @@ -0,0 +1,38 @@ +/* { dg-output "3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "add"] +pub trait Add { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; +} + +struct Foo(i32); + +impl Add for Foo { + type Output = Foo; + + fn add(self, other: Foo) -> Foo { + let res = Foo(self.0 + other.0); + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res.0); + } + + res + } +} + +fn main() -> i32 { + let a; + a = Foo(1) + Foo(2); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_3.rs b/gcc/testsuite/rust/execute/torture/operator_overload_3.rs new file mode 100644 index 00000000000..57f58076c3e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_3.rs @@ -0,0 +1,55 @@ +/* { dg-output "3\n3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "add"] +pub trait Add { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; +} + +impl Add for i32 { + type Output = i32; + + fn add(self, other: i32) -> i32 { + let res = self + other; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res); + } + + res + } +} + +struct Foo(i32); +impl Add for Foo { + type Output = Foo; + + fn add(self, other: Foo) -> Foo { + let res = Foo(self.0 + other.0); + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res.0); + } + + res + } +} + +fn main() -> i32 { + let a; + a = Foo(1) + Foo(2); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_4.rs b/gcc/testsuite/rust/execute/torture/operator_overload_4.rs new file mode 100644 index 00000000000..ce9887b2ead --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_4.rs @@ -0,0 +1,33 @@ +/* { dg-output "neg\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "neg"] +pub trait Neg { + type Output; + + fn neg(self) -> Self::Output; +} + +impl Neg for i32 { + type Output = i32; + + fn neg(self) -> i32 { + unsafe { + let a = "neg\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + -self + } +} + +fn main() -> i32 { + let a: i32 = 1; + let _b = -a; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_5.rs b/gcc/testsuite/rust/execute/torture/operator_overload_5.rs new file mode 100644 index 00000000000..a525f743680 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_5.rs @@ -0,0 +1,33 @@ +/* { dg-output "not\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "not"] +pub trait Not { + type Output; + + fn not(self) -> Self::Output; +} + +impl Not for i32 { + type Output = i32; + + fn not(self) -> i32 { + unsafe { + let a = "not\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + !self + } +} + +fn main() -> i32 { + let a: i32 = 1; + let _b = !a; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_6.rs b/gcc/testsuite/rust/execute/torture/operator_overload_6.rs new file mode 100644 index 00000000000..fbd2a8fa9d3 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_6.rs @@ -0,0 +1,37 @@ +/* { dg-output "add_assign\n3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "add_assign"] +pub trait AddAssign { + fn add_assign(&mut self, rhs: Rhs); +} + +impl AddAssign for i32 { + fn add_assign(&mut self, other: i32) { + unsafe { + let a = "add_assign\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + *self += other + } +} + +fn main() -> i32 { + let mut res = 1; + res += 2; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_7.rs b/gcc/testsuite/rust/execute/torture/operator_overload_7.rs new file mode 100644 index 00000000000..886a7010efc --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_7.rs @@ -0,0 +1,42 @@ +/* { dg-output "imm_deref\n123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "imm_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +fn main() -> i32 { + let foo: &i32 = &123; + let res: i32 = *foo; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_8.rs b/gcc/testsuite/rust/execute/torture/operator_overload_8.rs new file mode 100644 index 00000000000..862e29a4bc6 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_8.rs @@ -0,0 +1,58 @@ +/* { dg-output "imm_deref\n123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "imm_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +impl Deref for &mut T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +fn main() -> i32 { + let foo: &i32 = &123; + let res: i32 = *foo; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_9.rs b/gcc/testsuite/rust/execute/torture/operator_overload_9.rs new file mode 100644 index 00000000000..fd972e28ab3 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_9.rs @@ -0,0 +1,58 @@ +/* { dg-output "mut_deref\n123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "imm_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +impl Deref for &mut T { + type Target = T; + + fn deref(&self) -> &T { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + *self + } +} + +fn main() -> i32 { + let foo = &mut 123; + let res: i32 = *foo; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/slice-magic.rs b/gcc/testsuite/rust/execute/torture/slice-magic.rs new file mode 100644 index 00000000000..d1132989ddb --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/slice-magic.rs @@ -0,0 +1,106 @@ +// { dg-additional-options "-w" } +extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + pub fn offset(dst: *const T, offset: isize) -> *const T; +} + +struct FatPtr { + data: *const T, + len: usize, +} + +union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +#[lang = "Range"] +pub struct Range { + pub start: Idx, + pub end: Idx, +} + +#[lang = "const_slice_ptr"] +impl *const [A] { + pub const fn len(self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } + + pub const fn as_ptr(self) -> *const A { + self as *const A + } +} + +#[lang = "const_ptr"] +impl *const B { + pub const unsafe fn offset(self, count: isize) -> *const B { + unsafe { offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } + + pub const fn as_ptr(self) -> *const B { + self as *const B + } +} + +const fn slice_from_raw_parts(data: *const C, len: usize) -> *const [C] { + unsafe { + Repr { + raw: FatPtr { data, len }, + } + .rust + } +} + +#[lang = "index"] +trait Index { + type Output; + + fn index(&self, index: Idx) -> &Self::Output; +} + +pub unsafe trait SliceIndex { + type Output; + + unsafe fn get_unchecked(self, slice: *const X) -> *const Self::Output; + + fn index(self, slice: &X) -> &Self::Output; +} + +unsafe impl SliceIndex<[Y]> for Range { + type Output = [Y]; + + unsafe fn get_unchecked(self, slice: *const [Y]) -> *const [Y] { + unsafe { + let a: *const Y = slice.as_ptr(); + let b: *const Y = a.add(self.start); + slice_from_raw_parts(b, self.end - self.start) + } + } + + fn index(self, slice: &[Y]) -> &[Y] { + unsafe { &*self.get_unchecked(slice) } + } +} + +impl Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +fn main() -> i32 { + let a = [1, 2, 3, 4, 5]; + let b = &a[1..3]; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/slice-magic2.rs b/gcc/testsuite/rust/execute/torture/slice-magic2.rs new file mode 100644 index 00000000000..64a566185fa --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/slice-magic2.rs @@ -0,0 +1,106 @@ +// { dg-additional-options "-w" } +extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + pub fn offset(dst: *const T, offset: isize) -> *const T; +} + +struct FatPtr { + data: *const T, + len: usize, +} + +union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +#[lang = "Range"] +pub struct Range { + pub start: Idx, + pub end: Idx, +} + +#[lang = "const_slice_ptr"] +impl *const [T] { + pub const fn len(self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +#[lang = "const_ptr"] +impl *const T { + pub const unsafe fn offset(self, count: isize) -> *const T { + unsafe { offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { + unsafe { + Repr { + raw: FatPtr { data, len }, + } + .rust + } +} + +#[lang = "index"] +trait Index { + type Output; + + fn index(&self, index: Idx) -> &Self::Output; +} + +pub unsafe trait SliceIndex { + type Output; + + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; + + fn index(self, slice: &T) -> &Self::Output; +} + +unsafe impl SliceIndex<[T]> for Range { + type Output = [T]; + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + unsafe { + let a: *const T = slice.as_ptr(); + let b: *const T = a.add(self.start); + slice_from_raw_parts(b, self.end - self.start) + } + } + + fn index(self, slice: &[T]) -> &[T] { + unsafe { &*self.get_unchecked(slice) } + } +} + +impl Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +fn main() -> i32 { + let a = [1, 2, 3, 4, 5]; + let b = &a[1..3]; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/slice1.rs b/gcc/testsuite/rust/execute/torture/slice1.rs new file mode 100644 index 00000000000..a0488b3912c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/slice1.rs @@ -0,0 +1,27 @@ +// { dg-additional-options "-w" } +struct FatPtr { + data: *const T, + len: usize, +} + +union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { + unsafe { + let a = FatPtr { data, len }; + let b = Repr { raw: a }; + b.rust + } +} + +fn main() -> i32 { + let a = 123; + let b: *const i32 = &a; + let c = slice_from_raw_parts(b, 1); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/str-layout1.rs b/gcc/testsuite/rust/execute/torture/str-layout1.rs new file mode 100644 index 00000000000..80bdc2a9c9f --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/str-layout1.rs @@ -0,0 +1,57 @@ +// { dg-additional-options "-w" } +// { dg-output "t1sz=5 t2sz=10" } +mod mem { + extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_transmute", since = "1.46.0")] + fn transmute(_: T) -> U; + } +} + +extern "C" { + fn printf(s: *const i8, ...); +} + +struct FatPtr { + data: *const T, + len: usize, +} + +pub union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +impl [T] { + pub const fn len(&self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } +} + +impl str { + pub const fn len(&self) -> usize { + self.as_bytes().len() + } + + pub const fn as_bytes(&self) -> &[u8] { + unsafe { mem::transmute(self) } + } +} + +fn main() -> i32 { + let t1: &str = "TEST1"; + let t2: &str = &"TEST_12345"; + + let t1sz = t1.len(); + let t2sz = t2.len(); + + unsafe { + let a = "t1sz=%i t2sz=%i\n"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, t1sz as i32, t2sz as i32); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/str-zero.rs b/gcc/testsuite/rust/execute/torture/str-zero.rs new file mode 100644 index 00000000000..e7fba0d1372 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/str-zero.rs @@ -0,0 +1,26 @@ +/* { dg-output "bar foo baz foobar\n" } */ +extern "C" +{ + fn printf(s: *const i8, ...); + fn memchr(s: *const i8, c: u8, n: usize) -> *const i8; +} + +pub fn main () -> i32 +{ + let f = "%s %s %s %s\n\0"; + let s = "bar\0\ + foo\ + \x00\ + baz\u{0000}\ + foobar\0"; + let cf = f as *const str as *const i8; + let cs = s as *const str as *const i8; + unsafe + { + let cs2 = memchr (cs, b'f', 5); + let cs3 = memchr (cs2, b'b', 5); + let cs4 = memchr (cs3, b'f', 5); + printf (cf, cs, cs2, cs3, cs4); + } + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait1.rs b/gcc/testsuite/rust/execute/torture/trait1.rs new file mode 100644 index 00000000000..dc3cc471c33 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait1.rs @@ -0,0 +1,52 @@ +/* { dg-output "S::f\nT1::f\nT2::f\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct S; + +impl S { + fn f() { + unsafe { + let a = "S::f\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } +} + +trait T1 { + fn f() { + unsafe { + let a = "T1::f\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } +} +impl T1 for S {} + +trait T2 { + fn f() { + unsafe { + let a = "T2::f\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } +} +impl T2 for S {} + +fn main() -> i32 { + S::f(); + ::f(); + ::f(); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait10.rs b/gcc/testsuite/rust/execute/torture/trait10.rs new file mode 100644 index 00000000000..e581e324bbf --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait10.rs @@ -0,0 +1,41 @@ +/* { dg-output "123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(i32); +trait Bar { + fn baz(&self); +} + +impl Bar for Foo { + fn baz(&self) { + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, self.0); + } + } +} + +struct S; +impl S { + fn dynamic_dispatch(self, t: &dyn Bar) { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + t.baz(); + } +} + +pub fn main() -> i32 { + let a; + a = &Foo(123); + + let b; + b = S; + + b.dynamic_dispatch(a); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait11.rs b/gcc/testsuite/rust/execute/torture/trait11.rs new file mode 100644 index 00000000000..283c9ecd0ed --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait11.rs @@ -0,0 +1,38 @@ +/* { dg-output "3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +trait FnLike { + fn call(&self, arg: A) -> R; +} + +struct S; +impl<'a, T> FnLike<&'a T, &'a T> for S { + fn call(&self, arg: &'a T) -> &'a T { + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + arg + } +} + +fn indirect(f: F) +where + F: for<'a> FnLike<&'a isize, &'a isize>, +{ + let x = 3; + let y = f.call(&x); + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, *y); + } +} + +fn main() -> i32 { + indirect(S); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait12.rs b/gcc/testsuite/rust/execute/torture/trait12.rs new file mode 100644 index 00000000000..68b0a4014ad --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait12.rs @@ -0,0 +1,38 @@ +/* { dg-output "3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +trait FnLike { + fn call(&self, arg: A) -> R; +} + +type FnObject<'b> = dyn for<'a> FnLike<&'a isize, &'a isize> + 'b; + +struct Identity; + +impl<'a, T> FnLike<&'a T, &'a T> for Identity { + fn call(&self, arg: &'a T) -> &'a T { + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + arg + } +} + +fn call_repeatedly(f: &FnObject) { + let x = 3; + let y = f.call(&x); + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, *y); + } +} + +fn main() -> i32 { + call_repeatedly(&Identity); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait13.rs b/gcc/testsuite/rust/execute/torture/trait13.rs new file mode 100644 index 00000000000..3071da27a6a --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait13.rs @@ -0,0 +1,48 @@ +/* { dg-output "123\n456\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(i32); +trait Bar { + fn baz(&self); + + fn qux(&self) { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, 456); + } + } +} + +impl Bar for Foo { + fn baz(&self) { + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, self.0); + } + } +} + +fn dynamic_dispatch(t: &dyn Bar) { + t.baz(); + t.qux(); +} + +fn main() -> i32 { + let a; + a = Foo(123); + + let b: &dyn Bar; + b = &a; + dynamic_dispatch(b); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait2.rs b/gcc/testsuite/rust/execute/torture/trait2.rs new file mode 100644 index 00000000000..c96615fa891 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait2.rs @@ -0,0 +1,37 @@ +/* { dg-output "Bar::A = 456\n::A = 456\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +trait Foo { + const A: i32 = 123; +} + +struct Bar; +impl Foo for Bar { + const A: i32 = 456; +} + +fn main() -> i32 { + let a; + a = Bar::A; + + unsafe { + let _a = "Bar::A = %i\n\0"; + let _b = _a as *const str; + let _c = _b as *const i8; + printf(_c, a); + } + + let b; + b = ::A; + + unsafe { + let _a = "::A = %i\n\0"; + let _b = _a as *const str; + let _c = _b as *const i8; + printf(_c, b); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait3.rs b/gcc/testsuite/rust/execute/torture/trait3.rs new file mode 100644 index 00000000000..accfa9d0a36 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait3.rs @@ -0,0 +1,43 @@ +/* { dg-output "123, 777" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +trait A { + fn a() -> i32 { + 123 + } +} + +trait B: A { + fn b() -> i32 { + ::a() + 456 + } +} + +struct T; +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl A for T { + fn a() -> i32 { + 321 + } +} + +struct S; +impl A for S {} +impl B for S {} + +fn main() -> i32 { + let aa = S::a(); + let bb = S::b(); + + unsafe { + let a = "%i, %i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, aa, bb); + } + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait4.rs b/gcc/testsuite/rust/execute/torture/trait4.rs new file mode 100644 index 00000000000..8c0d257cd7e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait4.rs @@ -0,0 +1,34 @@ +/* { dg-output "123\n" }*/ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(i32); +trait Bar { + fn baz(&self); +} + +impl Bar for Foo { + fn baz(&self) { + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, self.0); + } + } +} + +fn type_bound(t: &T) { + t.baz(); +} + +fn main() -> i32 { + let a; + + a = &Foo(123); + type_bound(a); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait5.rs b/gcc/testsuite/rust/execute/torture/trait5.rs new file mode 100644 index 00000000000..49f11a6085a --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait5.rs @@ -0,0 +1,39 @@ +/* { dg-output "123\n123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +struct Foo(i32); +trait Bar { + fn baz(&self); +} + +impl Bar for Foo { + fn baz(&self) { + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, self.0); + } + } +} + +fn static_dispatch(t: &T) { + t.baz(); +} + +fn dynamic_dispatch(t: &dyn Bar) { + t.baz(); +} + +fn main() -> i32 { + let a = &Foo(123); + static_dispatch(a); + + let b: &dyn Bar = a; + dynamic_dispatch(b); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait6.rs b/gcc/testsuite/rust/execute/torture/trait6.rs new file mode 100644 index 00000000000..c83d6666c87 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait6.rs @@ -0,0 +1,39 @@ +/* { dg-output "123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +pub trait Foo { + type A; + + fn bar(self) -> Self::A; +} + +struct S(i32); +impl Foo for S { + type A = i32; + + fn bar(self) -> Self::A { + self.0 + } +} + +fn test_bar(x: T) -> T::A { + x.bar() +} + +fn main() -> i32 { + let a; + a = S(123); + + let bar: i32 = test_bar::(a); + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, bar); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait7.rs b/gcc/testsuite/rust/execute/torture/trait7.rs new file mode 100644 index 00000000000..064f88d5de9 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait7.rs @@ -0,0 +1,39 @@ +/* { dg-output "123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +pub trait Foo { + type A; + + fn bar(self) -> Self::A; +} + +struct S(i32); +impl Foo for S { + type A = i32; + + fn bar(self) -> Self::A { + self.0 + } +} + +fn test_bar(x: T) -> T::A { + x.bar() +} + +fn main() -> i32 { + let a; + a = S(123); + + let bar: i32 = test_bar(a); + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, bar); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait8.rs b/gcc/testsuite/rust/execute/torture/trait8.rs new file mode 100644 index 00000000000..14392ff0cca --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait8.rs @@ -0,0 +1,39 @@ +/* { dg-output "123\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +pub trait Foo { + type A; + + fn bar(&self) -> Self::A; +} + +struct S(i32); +impl Foo for S { + type A = i32; + + fn bar(&self) -> Self::A { + self.0 + } +} + +fn test_bar(x: T) -> T::A { + x.bar() +} + +fn main() -> i32 { + let a; + a = S(123); + + let bar: i32 = test_bar(a); + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, bar); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/trait9.rs b/gcc/testsuite/rust/execute/torture/trait9.rs new file mode 100644 index 00000000000..c0e6d36f183 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait9.rs @@ -0,0 +1,35 @@ +/* { dg-output "3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +trait FnLike { + fn call(&self, arg: A) -> R; +} + +struct S; +impl FnLike<&T, &T> for S { + fn call(&self, arg: &T) -> &T { + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + arg + } +} + +fn indirect>(f: F) { + let x = 3; + let y = f.call(&x); + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, *y); + } +} + +fn main() -> i32 { + indirect(S); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/transmute1.rs b/gcc/testsuite/rust/execute/torture/transmute1.rs new file mode 100644 index 00000000000..b9ec38ca618 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/transmute1.rs @@ -0,0 +1,23 @@ +// { dg-additional-options "-w" } + +extern "rust-intrinsic" { + fn transmute(value: T) -> U; +} + +struct WrapI { + inner: i32, +} + +struct WrapF { + inner: f32, +} + +fn main() -> i32 { + let f = 15.4f32; + let f_wrap = WrapF { inner: f }; + + let fst = unsafe { transmute::(f) }; + let snd = unsafe { transmute::(f_wrap) }; + + fst - snd.inner +} diff --git a/gcc/testsuite/rust/execute/torture/wrapping_op1.rs b/gcc/testsuite/rust/execute/torture/wrapping_op1.rs new file mode 100644 index 00000000000..64b37085ab7 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/wrapping_op1.rs @@ -0,0 +1,14 @@ +extern "rust-intrinsic" { + pub fn wrapping_add(l: T, r: T) -> T; +} + +fn five() -> u8 { + 5 +} + +fn main() -> u8 { + let l = 255; + let r = five(); + + unsafe { wrapping_add(l, r) - 4 } +} diff --git a/gcc/testsuite/rust/execute/torture/wrapping_op2.rs b/gcc/testsuite/rust/execute/torture/wrapping_op2.rs new file mode 100644 index 00000000000..f9990157894 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/wrapping_op2.rs @@ -0,0 +1,20 @@ +extern "rust-intrinsic" { + pub fn wrapping_add(l: T, r: T) -> T; + pub fn wrapping_sub(l: T, r: T) -> T; + pub fn wrapping_mul(l: T, r: T) -> T; +} + +fn five() -> u8 { + 5 +} + +fn main() -> u8 { + let l = 255; + let r = five(); + + let ret0 = unsafe { wrapping_add(l, r) - 4 }; // 4 + let ret1 = unsafe { wrapping_sub(r, l) - 6 }; // 6 + let ret2 = unsafe { wrapping_mul(r, l) - 251 }; // 251 + + ret0 + ret1 + ret2 +} diff --git a/gcc/testsuite/rust/execute/xfail/macro1.rs b/gcc/testsuite/rust/execute/xfail/macro1.rs new file mode 100644 index 00000000000..eab5a0285cf --- /dev/null +++ b/gcc/testsuite/rust/execute/xfail/macro1.rs @@ -0,0 +1,32 @@ +// { dg-output "macro\nmacro\nmacro\nmacro\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn f() { + let r_s = "macro\n\0"; + let s_p = r_s as *const str; + let c_p = s_p as *const i8; + + printf(c_p); +} + +macro_rules! empty0 { + () => ( f() ); +} + +macro_rules! empty1 { + {} => { f() }; +} + +macro_rules! empty2 { + [] => [ f() ]; +} + +// using multiple parens/brackets/curlies variants allows us to make sure we +// parse everything properly +fn main() { + empty0!(); + empty1!{}; + empty2![]; +} From patchwork Tue Dec 6 10:13:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61500 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 09D9139960C7 for ; Tue, 6 Dec 2022 10:12:45 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by sourceware.org (Postfix) with ESMTPS id 8DB80395C011 for ; Tue, 6 Dec 2022 10:11:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8DB80395C011 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x42b.google.com with SMTP id h11so22681196wrw.13 for ; Tue, 06 Dec 2022 02:11:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=3zm5KJY035CjcOsQSdplYxuyDzW/EVvguACCjSWfOs0=; b=hvm0ozAYZ9aE4lgDN/TJdEKYr3HaQpy2O8ePQv+KDZ4sZv6ji3SOOWAHYOm0OqWv5+ YI4CCMmMogRjFfma6miE+V+z/s1GYAOpl23whJKkI3UTWi02oRs8rYEMHXMGX1Xu/wCv UaNPItm0txdoAV8jvN2tHgOK+naXimxq0oZ/q81OIiQBaFgmFRnzFqf45t4NCaxLr5cV /41uA32XanT1khTDt1om5h5VROktlXxbQGtrtaVPWxhf6FEKSXmPsS3CeiED5/rUMcra 29jzlbi3m3DQhTxGWBPaGNF9p1zbczC+qms70g+lRAbUwCYN7ilZgS3YNjt4idQhYtiX v+mw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=3zm5KJY035CjcOsQSdplYxuyDzW/EVvguACCjSWfOs0=; b=EYX4kas004KfDaQR2Du0wrDnh5rCEk3qDfTHQfi3EdJsWnb+YooXzFqm7AJ7teI3OQ 3r90a2qbrYMY2YiXn6VySto9QN+GJ/pTdvCHS1uzne5m/YhAP3Z2FofY9R3ECzJPJ7Q8 aDCyQXg9X+IcKbHydewKeMeOQg2h4slQCDWvKQrPOuWJXrFHmMV84QqmgQ+Worhs7nQZ wyFALVh42ntsPSCEyyZbmpcgTTirUdElH/AVxS3jo7Rg7YxYYiMVnw+Z92kNtwg/Yvec xoeSg1HvCDhpLbm9tzg7jBH2W7xi+xdfPNoDYfJgYDe7z7CrlaSoWjK8KYNF73g/lx5+ ZuyA== X-Gm-Message-State: ANoB5pkmVOkfO0FfQb6ZqCyUBfm+RBVWu8ZYv/y91Lp/epfuoNIJUYWC 85ULZOBRFBNUyEslxer/lbQK24KJWhCt1k2/Hw== X-Google-Smtp-Source: AA0mqf7HjtSpybTwl82Z8o01/UBN5uE+0duI4OHMSKRnnEbDVxQfaCIBW+o3935/3eaR50Hp/dWY1w== X-Received: by 2002:a05:6000:149:b0:242:6b35:598e with SMTP id r9-20020a056000014900b002426b35598emr3658936wrx.47.1670321514875; Tue, 06 Dec 2022 02:11:54 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.11.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:11:54 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Philip Herron Subject: [PATCH Rust front-end v4 07/46] gccrs: Add gcc-check-target check-rust Date: Tue, 6 Dec 2022 11:13:39 +0100 Message-Id: <20221206101417.778807-8-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-35.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This allows us to invoke the rust testsuite. ChangeLog: * Makefile.def: Add Rust language. * Makefile.in: Regenerate via autogen. --- Makefile.def | 1 + Makefile.in | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/Makefile.def b/Makefile.def index 3291b126b26..821016af3a2 100644 --- a/Makefile.def +++ b/Makefile.def @@ -681,6 +681,7 @@ languages = { language=go; gcc-check-target=check-go; languages = { language=d; gcc-check-target=check-d; lib-check-target=check-target-libphobos; }; languages = { language=jit; gcc-check-target=check-jit; }; +languages = { language=rust; gcc-check-target=check-rust; }; // Toplevel bootstrap bootstrap_stage = { id=1 ; }; diff --git a/Makefile.in b/Makefile.in index 1919dfee829..9ed2c0dec52 100644 --- a/Makefile.in +++ b/Makefile.in @@ -60583,6 +60583,14 @@ check-gcc-jit: (cd gcc && $(MAKE) $(GCC_FLAGS_TO_PASS) check-jit); check-jit: check-gcc-jit +.PHONY: check-gcc-rust check-rust +check-gcc-rust: + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(HOST_EXPORTS) \ + (cd gcc && $(MAKE) $(GCC_FLAGS_TO_PASS) check-rust); +check-rust: check-gcc-rust + # The gcc part of install-no-fixedincludes, which relies on an intimate # knowledge of how a number of gcc internal targets (inter)operate. Delegate. From patchwork Tue Dec 6 10:13:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61507 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0B8E03AA9C4D for ; Tue, 6 Dec 2022 10:16:53 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by sourceware.org (Postfix) with ESMTPS id E5B0A395C061 for ; Tue, 6 Dec 2022 10:11:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E5B0A395C061 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wm1-x332.google.com with SMTP id c65-20020a1c3544000000b003cfffd00fc0so13927098wma.1 for ; Tue, 06 Dec 2022 02:11:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=IIcygeub+zzDqPOZq1mAHY00CwN7bO32XdOU4fVOk50=; b=OW5kXkMu4BaAesGvmlTe4U3pZOMHkLeXfiiPUFopfeObq4FFJWeQ/RUjjPhSFRnE24 6e7r7p7u7vgCPzs6oVkaoVbvgiEdVjwaAJ3KIaTUtyEyhJ0mmNcN/15glPsvk+fFnJlU LSs3Cad5Y5uOkS3B3vXxyXsVHGzxGyP2hRCDynY0SFHQKDs9GfsTuBYrxTSqSMiOchw/ apoWVAK5CHpnc5U9cVwb5xNT4o1832PL2aZ1Ls1D+ENKubduEKVqLLsJwIJIKHZBQjz8 ayR0xYeDkCdz3cXgPMS6VJ3zRyfrYDzwRAv7jcy8MkZdKucIAzZpqV0XkvlfvCF5JR/+ VK3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=IIcygeub+zzDqPOZq1mAHY00CwN7bO32XdOU4fVOk50=; b=SDBEKYI8Xf9Y66tlLVZzXvsvEInAuhe1qFyygNyUzNJYrYKWeqHy//OOqqTE4BGbYs E6ksyDhMK3MJHBK6KLCxgqbuRY+jZ579+vrzWUEBRh4Eh7gk+veBMLYdQqyuWPQsgOxe 4VqA3QKgtxlh+8C7PtX/J8PFpadqowCQrtzt8YwOUABrIK3UGYY+8ODM5x7cZU2ruInu ieAT5Hxezv/5OkuAZl5Pz4xsqW1iWOx53SIXJxc3rC1bHCyKOSE3ifEXXxTLba+Mdb1n Ji4I8ytVoVhzZrUluKG4QwXiFTgnVJtzBpRDDoORxWr0vdyf8I5SGX2GWdk8UHVDIOMD aNwQ== X-Gm-Message-State: ANoB5plMpEfnDl+tJ19qzE094rwxI+asDbI6fG0Pb5sdDVn9pIwHAIP8 mU3XtO7NPpb7AL5ljhJuJ94U5disWE3nofs3bg== X-Google-Smtp-Source: AA0mqf60eug2Anx5aR8v3nhdioDByLd4+oC+kPujuwI9rtsIdpM0upbCFxcE6ZKglJCD0+Jf7ERBag== X-Received: by 2002:a05:600c:3586:b0:3cf:a3b0:df6a with SMTP id p6-20020a05600c358600b003cfa3b0df6amr65318923wmq.126.1670321516904; Tue, 06 Dec 2022 02:11:56 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.11.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:11:55 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, The Other , Philip Herron Subject: [PATCH Rust front-end v4 08/46] gccrs: Add Rust front-end base AST data structures Date: Tue, 6 Dec 2022 11:13:40 +0100 Message-Id: <20221206101417.778807-9-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-19.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: The Other This is a full C++11 class hierarchy representing the Rust AST. We do not allow dynamic_cast and so the main mechanism to work with the AST is by using the visitor interface. Slowly we are adding TREE_CODE style node types to the AST which will allow for more ways to work with the AST but for now this is it. See: https://doc.rust-lang.org/reference/items.html Co-authored-by: Philip Herron Co-authored-by: Arthur Cohen . + +#ifndef RUST_AST_FULL_DECLS_H +#define RUST_AST_FULL_DECLS_H + +// Forward declarations for all AST classes. Useful for not having to include +// all definitions. + +namespace Rust { +namespace AST { +// rust-ast.h +class AttrInput; +class TokenTree; +class MacroMatch; +class Token; +struct Literal; +class DelimTokenTree; +class PathSegment; +class SimplePathSegment; +class SimplePath; +struct Attribute; +class MetaItemInner; +class AttrInputMetaItemContainer; +class MetaItem; +class Stmt; +class Item; +class Expr; +class ExprWithoutBlock; +class IdentifierExpr; +class Pattern; +class Type; +class TypeNoBounds; +class TypeParamBound; +class Lifetime; +class GenericParam; +class LifetimeParam; +class ConstGenericParam; +class MacroItem; +class TraitItem; +class InherentImplItem; +class TraitImplItem; +struct Crate; +class PathExpr; + +// rust-path.h +class PathIdentSegment; +struct GenericArgsBinding; +struct GenericArgs; +class PathExprSegment; +class PathPattern; +class PathInExpression; +class TypePathSegment; +class TypePathSegmentGeneric; +struct TypePathFunction; +class TypePathSegmentFunction; +class TypePath; +struct QualifiedPathType; +class QualifiedPathInExpression; +class QualifiedPathInType; + +// rust-expr.h +class ExprWithBlock; +class LiteralExpr; +class AttrInputLiteral; +class MetaItemLitExpr; +class MetaItemPathLit; +class OperatorExpr; +class BorrowExpr; +class DereferenceExpr; +class ErrorPropagationExpr; +class NegationExpr; +class ArithmeticOrLogicalExpr; +class ComparisonExpr; +class LazyBooleanExpr; +class TypeCastExpr; +class AssignmentExpr; +class CompoundAssignmentExpr; +class GroupedExpr; +class ArrayElems; +class ArrayElemsValues; +class ArrayElemsCopied; +class ArrayExpr; +class ArrayIndexExpr; +class TupleExpr; +class TupleIndexExpr; +class StructExpr; +class StructExprStruct; +struct StructBase; +class StructExprField; +class StructExprFieldIdentifier; +class StructExprFieldWithVal; +class StructExprFieldIdentifierValue; +class StructExprFieldIndexValue; +class StructExprStructFields; +class StructExprStructBase; +class CallExpr; +class MethodCallExpr; +class FieldAccessExpr; +struct ClosureParam; +class ClosureExpr; +class ClosureExprInner; +class BlockExpr; +class ClosureExprInnerTyped; +class ContinueExpr; +class BreakExpr; +class RangeExpr; +class RangeFromToExpr; +class RangeFromExpr; +class RangeToExpr; +class RangeFullExpr; +class RangeFromToInclExpr; +class RangeToInclExpr; +class ReturnExpr; +class UnsafeBlockExpr; +class LoopLabel; +class BaseLoopExpr; +class LoopExpr; +class WhileLoopExpr; +class WhileLetLoopExpr; +class ForLoopExpr; +class IfExpr; +class IfExprConseqElse; +class IfExprConseqIf; +class IfLetExpr; +class IfExprConseqIfLet; +class IfLetExprConseqElse; +class IfLetExprConseqIf; +class IfLetExprConseqIfLet; +struct MatchArm; +// class MatchCase; +// class MatchCaseBlockExpr; +// class MatchCaseExpr; +struct MatchCase; +class MatchExpr; +class AwaitExpr; +class AsyncBlockExpr; + +// rust-stmt.h +class EmptyStmt; +class LetStmt; +class ExprStmt; +class ExprStmtWithoutBlock; +class ExprStmtWithBlock; + +// rust-item.h +class TypeParam; +class WhereClauseItem; +class LifetimeWhereClauseItem; +class TypeBoundWhereClauseItem; +struct WhereClause; +struct SelfParam; +struct FunctionQualifiers; +struct FunctionParam; +struct Visibility; +class Method; +class VisItem; +class Module; +class ExternCrate; +class UseTree; +class UseTreeGlob; +class UseTreeList; +class UseTreeRebind; +class UseDeclaration; +class Function; +class TypeAlias; +class Struct; +struct StructField; +class StructStruct; +struct TupleField; +class TupleStruct; +class EnumItem; +class EnumItemTuple; +class EnumItemStruct; +class EnumItemDiscriminant; +class Enum; +class Union; +class ConstantItem; +class StaticItem; +struct TraitFunctionDecl; +class TraitItemFunc; +struct TraitMethodDecl; +class TraitItemMethod; +class TraitItemConst; +class TraitItemType; +class Trait; +class Impl; +class InherentImpl; +class TraitImpl; +class ExternalItem; +class ExternalStaticItem; +struct NamedFunctionParam; +class ExternalFunctionItem; +class ExternBlock; + +// rust-macro.h +class MacroMatchFragment; +class MacroMatchRepetition; +class MacroMatcher; +struct MacroTranscriber; +struct MacroRule; +class MacroRulesDefinition; +class MacroInvocation; +class MetaItemPath; +class MetaItemSeq; +class MetaWord; +class MetaNameValueStr; +class MetaListPaths; +class MetaListNameValueStr; + +// rust-pattern.h +class LiteralPattern; +class IdentifierPattern; +class WildcardPattern; +class RangePatternBound; +class RangePatternBoundLiteral; +class RangePatternBoundPath; +class RangePatternBoundQualPath; +class RangePattern; +class ReferencePattern; +struct StructPatternEtc; +class StructPatternField; +class StructPatternFieldTuplePat; +class StructPatternFieldIdentPat; +class StructPatternFieldIdent; +struct StructPatternElements; +class StructPattern; +class TupleStructItems; +class TupleStructItemsNoRange; +class TupleStructItemsRange; +class TupleStructPattern; +class TuplePatternItems; +class TuplePatternItemsMultiple; +class TuplePatternItemsRanged; +class TuplePattern; +class GroupedPattern; +class SlicePattern; + +// rust-type.h +class TraitBound; +class ImplTraitType; +class TraitObjectType; +class ParenthesisedType; +class ImplTraitTypeOneBound; +class TraitObjectTypeOneBound; +class TupleType; +class NeverType; +class RawPointerType; +class ReferenceType; +class ArrayType; +class SliceType; +class InferredType; +struct MaybeNamedParam; +class BareFunctionType; +} // namespace AST +} // namespace Rust + +#endif diff --git a/gcc/rust/ast/rust-ast-full-test.cc b/gcc/rust/ast/rust-ast-full-test.cc new file mode 100644 index 00000000000..1e8a93d462f --- /dev/null +++ b/gcc/rust/ast/rust-ast-full-test.cc @@ -0,0 +1,5810 @@ +/* General AST-related method implementations for Rust frontend. + Copyright (C) 2009-2022 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 +. */ + +#include "rust-system.h" +#include "rust-ast-full.h" +#include "rust-diagnostics.h" +#include "rust-ast-visitor.h" +#include "rust-macro.h" +#include "rust-session-manager.h" +#include "rust-lex.h" +#include "rust-parse.h" +#include "operator.h" + +/* Compilation unit used for various AST-related functions that would make + * the headers too long if they were defined inline and don't receive any + * benefits from being defined inline because they are virtual. Also used + * for various other stuff. */ + +namespace Rust { +namespace AST { + +enum indent_mode +{ + enter, + out, + stay +}; + +std::string +indent_spaces (enum indent_mode mode) +{ + static int indent = 0; + std::string str = ""; + if (out == mode) + indent--; + for (int i = 0; i < indent; i++) + str += " "; + if (enter == mode) + indent++; + + return str; +} + +// Gets a string in a certain delim type. +std::string +get_string_in_delims (std::string str_input, DelimType delim_type) +{ + switch (delim_type) + { + case PARENS: + return "(" + str_input + ")"; + case SQUARE: + return "[" + str_input + "]"; + case CURLY: + return "{" + str_input + "}"; + default: + return "ERROR-MARK-STRING (delims)"; + } + gcc_unreachable (); +} + +enum AttrMode +{ + OUTER, + INNER +}; + +std::string +get_mode_dump_desc (AttrMode mode) +{ + switch (mode) + { + case OUTER: + return "outer attributes"; + case INNER: + return "inner attributes"; + default: + gcc_unreachable (); + return ""; + } +} + +// Adds lines below adding attributes +std::string +append_attributes (std::vector attrs, AttrMode mode) +{ + indent_spaces (enter); + + std::string str + = "\n" + indent_spaces (stay) + get_mode_dump_desc (mode) + ": "; + // str += "\n" + indent_spaces (stay) + "inner attributes: "; + if (attrs.empty ()) + { + str += "none"; + } + else + { + /* note that this does not print them with outer or "inner attribute" + * syntax - just prints the body */ + for (const auto &attr : attrs) + str += "\n" + indent_spaces (stay) + attr.as_string (); + } + + indent_spaces (out); + + return str; +} + +// Removes the beginning and end quotes of a quoted string. +std::string +unquote_string (std::string input) +{ + rust_assert (input.front () == '"'); + rust_assert (input.back () == '"'); + return input.substr (1, input.length () - 2); +} + +std::string +Crate::as_string () const +{ + rust_debug ("beginning crate recursive as-string"); + + std::string str ("Crate: "); + + // inner attributes + str += append_attributes (inner_attrs, INNER); + + // items + str += "\n items: "; + if (items.empty ()) + { + str += "none"; + } + else + { + for (const auto &item : items) + { + // DEBUG: null pointer check + if (item == nullptr) + { + rust_debug ("something really terrible has gone wrong - " + "null pointer item in crate."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + item->as_string (); + } + } + + return str + "\n"; +} + +std::string +Attribute::as_string () const +{ + std::string path_str = path.as_string (); + if (attr_input == nullptr) + return path_str; + else + return path_str + attr_input->as_string (); +} + +// Copy constructor must deep copy attr_input as unique pointer +Attribute::Attribute (Attribute const &other) + : path (other.path), locus (other.locus) +{ + // guard to protect from null pointer dereference + if (other.attr_input != nullptr) + attr_input = other.attr_input->clone_attr_input (); +} + +// overload assignment operator to use custom clone method +Attribute & +Attribute::operator= (Attribute const &other) +{ + path = other.path; + locus = other.locus; + // guard to protect from null pointer dereference + if (other.attr_input != nullptr) + attr_input = other.attr_input->clone_attr_input (); + else + attr_input = nullptr; + + return *this; +} + +std::string +DelimTokenTree::as_string () const +{ + std::string start_delim; + std::string end_delim; + switch (delim_type) + { + case PARENS: + start_delim = "("; + end_delim = ")"; + break; + case SQUARE: + start_delim = "["; + end_delim = "]"; + break; + case CURLY: + start_delim = "{"; + end_delim = "}"; + break; + default: + rust_debug ("Invalid delimiter type, " + "Should be PARENS, SQUARE, or CURLY."); + return "Invalid delimiter type"; + } + std::string str = start_delim; + if (!token_trees.empty ()) + { + for (const auto &tree : token_trees) + { + // DEBUG: null pointer check + if (tree == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "token tree in delim token tree."); + return "NULL_POINTER_MARK"; + } + + str += tree->as_string (); + } + } + str += end_delim; + + return str; +} + +std::string +Token::as_string () const +{ + if (tok_ref->has_str ()) + { + std::string str = tok_ref->get_str (); + + std::string quote = is_string_lit () ? "\"" : ""; + return quote + str + quote; + } + else + { + return tok_ref->get_token_description (); + } +} + +std::string +SimplePathSegment::as_string () const +{ + return segment_name; +} + +std::string +SimplePath::as_string () const +{ + std::string path; + if (has_opening_scope_resolution) + path = "::"; + + // crappy hack because doing proper for loop would be more code + bool first_time = true; + for (const auto &segment : segments) + { + if (first_time) + { + path += segment.as_string (); + first_time = false; + } + else + { + path += "::" + segment.as_string (); + } + + // DEBUG: remove later. Checks for path error. + if (segment.is_error ()) + { + rust_debug ("segment in path is error - this should've been filtered " + "out. first segment " + "was '%s'", + segments.at (0).as_string ().c_str ()); + } + } + + return path; +} + +std::string +Visibility::as_string () const +{ + switch (vis_type) + { + case PRIV: + return std::string (""); + case PUB: + return std::string ("pub"); + case PUB_CRATE: + return std::string ("pub(crate)"); + case PUB_SELF: + return std::string ("pub(self)"); + case PUB_SUPER: + return std::string ("pub(super)"); + case PUB_IN_PATH: + return std::string ("pub(in ") + in_path.as_string () + std::string (")"); + default: + gcc_unreachable (); + } +} + +// Creates a string that reflects the visibility stored. +std::string +VisItem::as_string () const +{ + // FIXME: can't do formatting on string to make identation occur. + std::string str; + + if (!outer_attrs.empty ()) + { + for (const auto &attr : outer_attrs) + str += attr.as_string () + "\n"; + } + + if (has_visibility ()) + str += visibility.as_string () + " "; + + return str; +} + +std::string +Module::as_string () const +{ + std::string str = VisItem::as_string () + "mod " + module_name; + + // Return early if we're dealing with an unloaded module as their body resides + // in a different file + if (kind == ModuleKind::UNLOADED) + return str + "\n no body (reference to external file)\n"; + + // inner attributes + str += append_attributes (inner_attrs, INNER); + + // items + str += "\n items: "; + + // This can still happen if the module is loaded but empty, i.e. `mod foo {}` + if (items.empty ()) + { + str += "none"; + } + else + { + for (const auto &item : items) + { + // DEBUG: null pointer check + if (item == nullptr) + { + rust_debug ("something really terrible has gone wrong - " + "null pointer item in crate."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + item->as_string (); + } + } + + return str + "\n"; +} + +std::string +StaticItem::as_string () const +{ + std::string str = VisItem::as_string (); + + str += indent_spaces (stay) + "static"; + + if (has_mut) + str += " mut"; + + str += " " + name; + + // DEBUG: null pointer check + if (type == nullptr) + { + rust_debug ("something really terrible has gone wrong - null " + "pointer type in static item."); + return "NULL_POINTER_MARK"; + } + str += "\n" + indent_spaces (stay) + "Type: " + type->as_string (); + + // DEBUG: null pointer check + if (expr == nullptr) + { + rust_debug ("something really terrible has gone wrong - null " + "pointer expr in static item."); + return "NULL_POINTER_MARK"; + } + str += "\n" + indent_spaces (stay) + "Expression: " + expr->as_string (); + + return str + "\n"; +} + +std::string +ExternCrate::as_string () const +{ + std::string str = VisItem::as_string (); + + str += "extern crate " + referenced_crate; + + if (has_as_clause ()) + str += " as " + as_clause_name; + + return str; +} + +std::string +TupleStruct::as_string () const +{ + std::string str = VisItem::as_string (); + + str += "struct " + struct_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + { + // DEBUG: null pointer check + if (param == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "generic param in enum."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string (); + } + } + + // tuple fields + str += "\n Tuple fields: "; + if (fields.empty ()) + { + str += "none"; + } + else + { + for (const auto &field : fields) + str += "\n " + field.as_string (); + } + + str += "\n Where clause: "; + if (has_where_clause ()) + str += where_clause.as_string (); + else + str += "none"; + + return str; +} + +std::string +ConstantItem::as_string () const +{ + std::string str = VisItem::as_string (); + + str += "const " + identifier; + + // DEBUG: null pointer check + if (type == nullptr) + { + rust_debug ("something really terrible has gone wrong - null " + "pointer type in const item."); + return "NULL_POINTER_MARK"; + } + str += "\n Type: " + type->as_string (); + + // DEBUG: null pointer check + if (const_expr == nullptr) + { + rust_debug ("something really terrible has gone wrong - null " + "pointer expr in const item."); + return "NULL_POINTER_MARK"; + } + str += "\n Expression: " + const_expr->as_string (); + + return str + "\n"; +} + +std::string +InherentImpl::as_string () const +{ + std::string str = VisItem::as_string (); + + str += "impl "; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + { + // DEBUG: null pointer check + if (param == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "generic param in inherent impl."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string (); + } + } + + str += "\n Type: " + trait_type->as_string (); + + str += "\n Where clause: "; + if (has_where_clause ()) + str += where_clause.as_string (); + else + str += "none"; + + // inner attributes + str += append_attributes (inner_attrs, INNER); + + // inherent impl items + str += "\n Inherent impl items: "; + if (!has_impl_items ()) + { + str += "none"; + } + else + { + for (const auto &item : impl_items) + str += "\n " + item->as_string (); + } + + return str; +} + +std::string +Method::as_string () const +{ + std::string str ("Method: \n "); + + str += vis.as_string () + " " + qualifiers.as_string (); + + str += " fn " + method_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + { + // DEBUG: null pointer check + if (param == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "generic param in method."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string (); + } + } + + str += "\n Self param: " + self_param.as_string (); + + str += "\n Function params: "; + if (function_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : function_params) + str += "\n " + param.as_string (); + } + + str += "\n Return type: "; + if (has_return_type ()) + str += return_type->as_string (); + else + str += "none (void)"; + + str += "\n Where clause: "; + if (has_where_clause ()) + str += where_clause.as_string (); + else + str += "none"; + + str += "\n Block expr (body): \n "; + str += function_body->as_string (); + + return str; +} + +std::string +StructStruct::as_string () const +{ + std::string str = VisItem::as_string (); + + str += "struct " + struct_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + { + // DEBUG: null pointer check + if (param == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "generic param in enum."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string (); + } + } + + str += "\n Where clause: "; + if (has_where_clause ()) + str += where_clause.as_string (); + else + str += "none"; + + // struct fields + str += "\n Struct fields: "; + if (is_unit) + { + str += "none (unit)"; + } + else if (fields.empty ()) + { + str += "none (non-unit)"; + } + else + { + for (const auto &field : fields) + str += "\n " + field.as_string (); + } + + return str; +} + +std::string +UseDeclaration::as_string () const +{ + std::string str = VisItem::as_string (); + + // DEBUG: null pointer check + if (use_tree == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer use tree in " + "use declaration."); + return "NULL_POINTER_MARK"; + } + + str += "use " + use_tree->as_string (); + + return str; +} + +std::string +UseTreeGlob::as_string () const +{ + switch (glob_type) + { + case NO_PATH: + return "*"; + case GLOBAL: + return "::*"; + case PATH_PREFIXED: { + std::string path_str = path.as_string (); + return path_str + "::*"; + } + default: + // some kind of error + return "ERROR-PATH"; + } + gcc_unreachable (); +} + +std::string +UseTreeList::as_string () const +{ + std::string path_str; + switch (path_type) + { + case NO_PATH: + path_str = "{"; + break; + case GLOBAL: + path_str = "::{"; + break; + case PATH_PREFIXED: { + path_str = path.as_string () + "::{"; + break; + } + default: + // some kind of error + return "ERROR-PATH-LIST"; + } + + if (has_trees ()) + { + auto i = trees.begin (); + auto e = trees.end (); + + // DEBUG: null pointer check + if (*i == nullptr) + { + rust_debug ("something really terrible has gone wrong - null pointer " + "tree in use tree list."); + return "NULL_POINTER_MARK"; + } + + for (; i != e; i++) + { + path_str += (*i)->as_string (); + if (e != i + 1) + path_str += ", "; + } + } + else + { + path_str += "none"; + } + + return path_str + "}"; +} + +std::string +UseTreeRebind::as_string () const +{ + std::string path_str = path.as_string (); + + switch (bind_type) + { + case NONE: + // nothing to add, just path + break; + case IDENTIFIER: + path_str += " as " + identifier; + break; + case WILDCARD: + path_str += " as _"; + break; + default: + // error + return "ERROR-PATH-REBIND"; + } + + return path_str; +} + +std::string +Enum::as_string () const +{ + std::string str = VisItem::as_string (); + str += enum_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + { + // DEBUG: null pointer check + if (param == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "generic param in enum."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string (); + } + } + + str += "\n Where clause: "; + if (has_where_clause ()) + str += where_clause.as_string (); + else + str += "none"; + + // items + str += "\n Items: "; + if (items.empty ()) + { + str += "none"; + } + else + { + for (const auto &item : items) + { + // DEBUG: null pointer check + if (item == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "enum item in enum."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + item->as_string (); + } + } + + return str; +} + +std::string +Trait::as_string () const +{ + std::string str = VisItem::as_string (); + + if (has_unsafe) + str += "unsafe "; + + str += "trait " + name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + { + // DEBUG: null pointer check + if (param == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "generic param in trait."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string (); + } + } + + str += "\n Type param bounds: "; + if (!has_type_param_bounds ()) + { + str += "none"; + } + else + { + for (const auto &bound : type_param_bounds) + { + // DEBUG: null pointer check + if (bound == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "type param bound in trait."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + bound->as_string (); + } + } + + str += "\n Where clause: "; + if (!has_where_clause ()) + str += "none"; + else + str += where_clause.as_string (); + + str += "\n Trait items: "; + if (!has_trait_items ()) + { + str += "none"; + } + else + { + for (const auto &item : trait_items) + { + // DEBUG: null pointer check + if (item == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "trait item in trait."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + item->as_string (); + } + } + + return str; +} + +std::string +Union::as_string () const +{ + std::string str = VisItem::as_string (); + + str += "union " + union_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + { + // DEBUG: null pointer check + if (param == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "generic param in union."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string (); + } + } + + str += "\n Where clause: "; + if (has_where_clause ()) + str += where_clause.as_string (); + else + str += "none"; + + // struct fields + str += "\n Struct fields (variants): "; + if (variants.empty ()) + { + str += "none"; + } + else + { + for (const auto &field : variants) + str += "\n " + field.as_string (); + } + + return str; +} + +std::string +Function::as_string () const +{ + std::string str = VisItem::as_string () + "\n"; + std::string qstr = qualifiers.as_string (); + if ("" != qstr) + str += qstr + " "; + + if (has_return_type ()) + { + // DEBUG: null pointer check + if (return_type == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer return " + "type in function."); + return "NULL_POINTER_MARK"; + } + + str += return_type->as_string () + " "; + } + else + { + str += "void "; + } + + str += function_name; + + if (has_generics ()) + { + str += "<"; + + auto i = generic_params.begin (); + auto e = generic_params.end (); + + // DEBUG: null pointer check + if (i == e) + { + rust_debug ("something really terrible has gone wrong - null pointer " + "generic param in function item."); + return "NULL_POINTER_MARK"; + } + + for (; i != e; i++) + { + str += (*i)->as_string (); + if (e != i + 1) + str += ", "; + } + str += ">"; + } + + if (has_function_params ()) + { + auto i = function_params.begin (); + auto e = function_params.end (); + str += "("; + for (; i != e; i++) + { + str += (*i).as_string (); + if (e != i + 1) + str += ", "; + } + str += ")"; + } + else + { + str += "()"; + } + + if (has_where_clause ()) + str += " where " + where_clause.as_string (); + + str += "\n"; + + // DEBUG: null pointer check + if (function_body == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer function " + "body in function."); + return "NULL_POINTER_MARK"; + } + str += function_body->as_string () + "\n"; + + return str; +} + +std::string +WhereClause::as_string () const +{ + // just print where clause items, don't mention "where" or "where clause" + std::string str; + + if (where_clause_items.empty ()) + { + str = "none"; + } + else + { + for (const auto &item : where_clause_items) + str += "\n " + item->as_string (); + } + + return str; +} + +std::string +BlockExpr::as_string () const +{ + std::string istr = indent_spaces (enter); + std::string str = istr + "BlockExpr:\n" + istr; + + // get outer attributes + str += append_attributes (outer_attrs, OUTER); + + // inner attributes + str += append_attributes (inner_attrs, INNER); + + // statements + str += "\n" + indent_spaces (stay) + "statements: "; + if (statements.empty ()) + { + str += "none"; + } + else + { + for (const auto &stmt : statements) + { + // DEBUG: null pointer check + if (stmt == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "stmt in block expr."); + return "NULL_POINTER_MARK"; + } + + str += "\n" + indent_spaces (stay) + stmt->as_string (); + } + } + + // final expression + str += "\n" + indent_spaces (stay) + "final expression: "; + if (expr == nullptr) + str += "none"; + else + str += "\n" + expr->as_string (); + + str += "\n" + indent_spaces (out); + return str; +} + +std::string +TraitImpl::as_string () const +{ + std::string str = VisItem::as_string (); + + if (has_unsafe) + str += "unsafe "; + + str += "impl "; + + // generic params + str += "\n Generic params: "; + if (!has_generics ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + str += "\n " + param->as_string (); + } + + str += "\n Has exclam: "; + if (has_exclam) + str += "true"; + else + str += "false"; + + str += "\n TypePath (to trait): " + trait_path.as_string (); + + str += "\n Type (struct to impl on): " + trait_type->as_string (); + + str += "\n Where clause: "; + if (!has_where_clause ()) + str += "none"; + else + str += where_clause.as_string (); + + // inner attributes + str += append_attributes (inner_attrs, INNER); + + str += "\n trait impl items: "; + if (!has_impl_items ()) + { + str += "none"; + } + else + { + for (const auto &item : impl_items) + str += "\n " + item->as_string (); + } + + return str; +} + +std::string +TypeAlias::as_string () const +{ + std::string str = VisItem::as_string (); + + str += " " + new_type_name; + + // generic params + str += "\n Generic params: "; + if (!has_generics ()) + { + str += "none"; + } + else + { + auto i = generic_params.begin (); + auto e = generic_params.end (); + + for (; i != e; i++) + { + str += (*i)->as_string (); + if (e != i + 1) + str += ", "; + } + } + + str += "\n Where clause: "; + if (!has_where_clause ()) + str += "none"; + else + str += where_clause.as_string (); + + str += "\n Type: " + existing_type->as_string (); + + return str; +} + +std::string +ExternBlock::as_string () const +{ + std::string str = VisItem::as_string (); + + str += "extern "; + if (has_abi ()) + str += "\"" + abi + "\" "; + + str += append_attributes (inner_attrs, INNER); + + str += "\n external items: "; + if (!has_extern_items ()) + { + str += "none"; + } + else + { + for (const auto &item : extern_items) + str += "\n " + item->as_string (); + } + + return str; +} + +std::string +MacroRule::as_string () const +{ + std::string str ("Macro rule: "); + + str += "\n Matcher: \n "; + str += matcher.as_string (); + + str += "\n Transcriber: \n "; + str += transcriber.as_string (); + + return str; +} + +std::string +MacroRulesDefinition::as_string () const +{ + std::string str; + + // get outer attrs + str += append_attributes (outer_attrs, OUTER); + + str += "macro_rules!"; + + str += rule_name; + + str += "\n Macro rules: "; + if (rules.empty ()) + { + str += "none"; + } + else + { + for (const auto &rule : rules) + str += "\n " + rule.as_string (); + } + + str += "\n Delim type: "; + switch (delim_type) + { + case PARENS: + str += "parentheses"; + break; + case SQUARE: + str += "square"; + break; + case CURLY: + str += "curly"; + break; + default: + return "ERROR_MARK_STRING - delim type in macro invocation"; + } + + return str; +} + +std::string +MacroInvocation::as_string () const +{ + std::string str = "MacroInvocation: "; + + str += append_attributes (outer_attrs, OUTER); + + str += "\n " + invoc_data.as_string (); + + str += "\n has semicolon: "; + str += has_semicolon () ? "true" : "false"; + + return str; +} + +std::string +MacroInvocData::as_string () const +{ + return path.as_string () + "!" + token_tree.as_string (); +} + +std::string +PathInExpression::as_string () const +{ + std::string str; + + if (has_opening_scope_resolution) + str = "::"; + + return str + PathPattern::as_string (); +} + +std::string +ExprStmtWithBlock::as_string () const +{ + std::string str = indent_spaces (enter) + "ExprStmtWithBlock: \n"; + + if (expr == nullptr) + { + str += "none (this should not happen and is an error)"; + } + else + { + indent_spaces (enter); + str += expr->as_string (); + indent_spaces (out); + } + + indent_spaces (out); + return str; +} + +std::string +ClosureParam::as_string () const +{ + std::string str (pattern->as_string ()); + + if (has_type_given ()) + str += " : " + type->as_string (); + + return str; +} + +std::string +ClosureExpr::as_string () const +{ + std::string str = "ClosureExpr:"; + + str += append_attributes (outer_attrs, OUTER); + + str += "\n Has move: "; + if (has_move) + str += "true"; + else + str += "false"; + + str += "\n Params: "; + if (params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : params) + str += "\n " + param.as_string (); + } + + return str; +} + +std::string +ClosureExprInnerTyped::as_string () const +{ + std::string str = ClosureExpr::as_string (); + + str += "\n Return type: " + return_type->as_string (); + + str += "\n Body: " + expr->as_string (); + + return str; +} + +std::string +PathPattern::as_string () const +{ + std::string str; + + for (const auto &segment : segments) + str += segment.as_string () + "::"; + + // basically a hack - remove last two characters of string (remove final ::) + str.erase (str.length () - 2); + + return str; +} + +std::string +QualifiedPathType::as_string () const +{ + std::string str ("<"); + str += type_to_invoke_on->as_string (); + + if (has_as_clause ()) + str += " as " + trait_path.as_string (); + + return str + ">"; +} + +std::string +QualifiedPathInExpression::as_string () const +{ + return path_type.as_string () + "::" + PathPattern::as_string (); +} + +std::string +BorrowExpr::as_string () const +{ + /* TODO: find way to incorporate outer attrs - may have to represent in + * different style (i.e. something more like BorrowExpr: \n outer attrs) */ + + std::string str ("&"); + + if (double_borrow) + str += "&"; + + if (is_mut) + str += "mut "; + + str += main_or_left_expr->as_string (); + + return str; +} + +std::string +ReturnExpr::as_string () const +{ + /* TODO: find way to incorporate outer attrs - may have to represent in + * different style (i.e. something more like BorrowExpr: \n outer attrs) */ + + std::string str ("return "); + + if (has_returned_expr ()) + str += return_expr->as_string (); + + return str; +} + +std::string +GroupedExpr::as_string () const +{ + std::string str ("Grouped expr:"); + + // outer attrs + str += append_attributes (outer_attrs, OUTER); + + // inner attributes + str += append_attributes (inner_attrs, INNER); + + str += "\n Expr in parens: " + expr_in_parens->as_string (); + + return str; +} + +std::string +RangeToExpr::as_string () const +{ + return ".." + to->as_string (); +} + +std::string +ContinueExpr::as_string () const +{ + // TODO: rewrite format to allow outer attributes + std::string str ("continue "); + + if (has_label ()) + str += label.as_string (); + + return str; +} + +std::string +NegationExpr::as_string () const +{ + // TODO: rewrite formula to allow outer attributes + std::string str; + + switch (expr_type) + { + case NegationOperator::NEGATE: + str = "-"; + break; + case NegationOperator::NOT: + str = "!"; + break; + default: + return "ERROR_MARK_STRING - negation expr"; + } + + str += main_or_left_expr->as_string (); + + return str; +} + +std::string +RangeFromExpr::as_string () const +{ + return from->as_string () + ".."; +} + +std::string +RangeFullExpr::as_string () const +{ + return ".."; +} + +std::string +ArrayIndexExpr::as_string () const +{ + // TODO: rewrite formula to allow outer attributes + return array_expr->as_string () + "[" + index_expr->as_string () + "]"; +} + +std::string +AssignmentExpr::as_string () const +{ + std::string str ("AssignmentExpr: "); + + if (main_or_left_expr == nullptr || right_expr == nullptr) + { + str += "error (either or both expressions are null)"; + } + else + { + // left expr + str += "\n left: " + main_or_left_expr->as_string (); + + // right expr + str += "\n right: " + right_expr->as_string (); + } + + return str; +} + +std::string +AsyncBlockExpr::as_string () const +{ + std::string str = "AsyncBlockExpr: "; + + // get outer attributes + // str += "\n " + Expr::as_string (); + str += append_attributes (outer_attrs, OUTER); + + str += "\n Has move: "; + str += has_move ? "true" : "false"; + + return str + "\n" + block_expr->as_string (); +} + +std::string +ComparisonExpr::as_string () const +{ + // TODO: rewrite to better reflect non-literal expressions + std::string str (main_or_left_expr->as_string ()); + + switch (expr_type) + { + case ComparisonOperator::EQUAL: + str += " == "; + break; + case ComparisonOperator::NOT_EQUAL: + str += " != "; + break; + case ComparisonOperator::GREATER_THAN: + str += " > "; + break; + case ComparisonOperator::LESS_THAN: + str += " < "; + break; + case ComparisonOperator::GREATER_OR_EQUAL: + str += " >= "; + break; + case ComparisonOperator::LESS_OR_EQUAL: + str += " <= "; + break; + default: + return "ERROR_MARK_STRING - comparison expr"; + } + + str += right_expr->as_string (); + + return str; +} + +std::string +MethodCallExpr::as_string () const +{ + std::string str = "MethodCallExpr: "; + + str += append_attributes (outer_attrs, OUTER); + + str += "\n Object (receiver) expr: \n"; + str += receiver->as_string (); + + str += "\n Method path segment: \n"; + str += method_name.as_string (); + + str += "\n Call params:"; + if (params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : params) + { + if (param == nullptr) + return "ERROR_MARK_STRING - method call expr param is null"; + + str += "\n " + param->as_string (); + } + } + + return str; +} + +std::string +TupleIndexExpr::as_string () const +{ + // TODO: rewrite dump to better reflect non-literal exprs + return tuple_expr->as_string () + "." + std::to_string (tuple_index); +} + +std::string +DereferenceExpr::as_string () const +{ + // TODO: rewrite dump to better reflect non-literal exprs + return "*" + main_or_left_expr->as_string (); +} + +std::string +FieldAccessExpr::as_string () const +{ + // TODO: rewrite dump to better reflect non-literal exprs + return receiver->as_string () + "." + field; +} + +std::string +LazyBooleanExpr::as_string () const +{ + // TODO: rewrite dump to better reflect non-literal exprs + std::string str (main_or_left_expr->as_string ()); + + switch (expr_type) + { + case LazyBooleanOperator::LOGICAL_OR: + str += " || "; + break; + case LazyBooleanOperator::LOGICAL_AND: + str += " && "; + break; + default: + return "ERROR_MARK_STRING - lazy boolean expr out of bounds"; + } + + str += right_expr->as_string (); + + return str; +} + +std::string +RangeFromToExpr::as_string () const +{ + // TODO: rewrite dump to better reflect non-literal exprs + return from->as_string () + ".." + to->as_string (); +} + +std::string +RangeToInclExpr::as_string () const +{ + // TODO: rewrite dump to better reflect non-literal exprs + return "..=" + to->as_string (); +} + +std::string +UnsafeBlockExpr::as_string () const +{ + std::string str = "UnsafeBlockExpr:" + indent_spaces (enter); + + // get outer attributes + str += append_attributes (outer_attrs, OUTER); + + str += indent_spaces (stay) + expr->as_string () + "\n" + indent_spaces (out); + + return str; +} + +std::string +ClosureExprInner::as_string () const +{ + std::string str = ClosureExpr::as_string (); + + str += "\n Expression: " + closure_inner->as_string (); + + return str; +} + +std::string +IfExpr::as_string () const +{ + std::string str = "IfExpr: "; + + str += append_attributes (outer_attrs, OUTER); + + str += "\n Condition expr: " + condition->as_string (); + + str += "\n If block expr: " + if_block->as_string (); + + return str; +} + +std::string +IfExprConseqElse::as_string () const +{ + std::string str = IfExpr::as_string (); + + str += "\n Else block expr: " + else_block->as_string (); + + return str; +} + +std::string +IfExprConseqIf::as_string () const +{ + std::string str = IfExpr::as_string (); + + str += "\n Else if expr: \n " + conseq_if_expr->as_string (); + + return str; +} + +std::string +IfExprConseqIfLet::as_string () const +{ + std::string str = IfExpr::as_string (); + + str += "\n Else if let expr: \n " + if_let_expr->as_string (); + + return str; +} + +std::string +IfLetExpr::as_string () const +{ + std::string str = "IfLetExpr: "; + + str += append_attributes (outer_attrs, OUTER); + + str += "\n Condition match arm patterns: "; + if (match_arm_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &pattern : match_arm_patterns) + str += "\n " + pattern->as_string (); + } + + str += "\n Scrutinee expr: " + value->as_string (); + + str += "\n If let block expr: " + if_block->as_string (); + + return str; +} + +std::string +IfLetExprConseqElse::as_string () const +{ + std::string str = IfLetExpr::as_string (); + + str += "\n Else block expr: " + else_block->as_string (); + + return str; +} + +std::string +IfLetExprConseqIf::as_string () const +{ + std::string str = IfLetExpr::as_string (); + + str += "\n Else if expr: \n " + if_expr->as_string (); + + return str; +} + +std::string +IfLetExprConseqIfLet::as_string () const +{ + std::string str = IfLetExpr::as_string (); + + str += "\n Else if let expr: \n " + if_let_expr->as_string (); + + return str; +} + +std::string +RangeFromToInclExpr::as_string () const +{ + // TODO: rewrite to allow dumps with non-literal exprs + return from->as_string () + "..=" + to->as_string (); +} + +std::string +ErrorPropagationExpr::as_string () const +{ + // TODO: rewrite to allow dumps with non-literal exprs + return main_or_left_expr->as_string () + "?"; +} + +std::string +CompoundAssignmentExpr::as_string () const +{ + std::string operator_str; + operator_str.reserve (1); + + // get operator string + switch (expr_type) + { + case CompoundAssignmentOperator::ADD: + operator_str = "+"; + break; + case CompoundAssignmentOperator::SUBTRACT: + operator_str = "-"; + break; + case CompoundAssignmentOperator::MULTIPLY: + operator_str = "*"; + break; + case CompoundAssignmentOperator::DIVIDE: + operator_str = "/"; + break; + case CompoundAssignmentOperator::MODULUS: + operator_str = "%"; + break; + case CompoundAssignmentOperator::BITWISE_AND: + operator_str = "&"; + break; + case CompoundAssignmentOperator::BITWISE_OR: + operator_str = "|"; + break; + case CompoundAssignmentOperator::BITWISE_XOR: + operator_str = "^"; + break; + case CompoundAssignmentOperator::LEFT_SHIFT: + operator_str = "<<"; + break; + case CompoundAssignmentOperator::RIGHT_SHIFT: + operator_str = ">>"; + break; + default: + operator_str = "invalid operator. wtf"; + break; + } + + operator_str += "="; + + std::string str ("CompoundAssignmentExpr: "); + if (main_or_left_expr == nullptr || right_expr == nullptr) + { + str += "error. this is probably a parsing failure."; + } + else + { + str += "\n left: " + main_or_left_expr->as_string (); + str += "\n right: " + right_expr->as_string (); + str += "\n operator: " + operator_str; + } + + return str; +} + +std::string +ArithmeticOrLogicalExpr::as_string () const +{ + std::string operator_str; + operator_str.reserve (1); + + // get operator string + switch (expr_type) + { + case ArithmeticOrLogicalOperator::ADD: + operator_str = "+"; + break; + case ArithmeticOrLogicalOperator::SUBTRACT: + operator_str = "-"; + break; + case ArithmeticOrLogicalOperator::MULTIPLY: + operator_str = "*"; + break; + case ArithmeticOrLogicalOperator::DIVIDE: + operator_str = "/"; + break; + case ArithmeticOrLogicalOperator::MODULUS: + operator_str = "%"; + break; + case ArithmeticOrLogicalOperator::BITWISE_AND: + operator_str = "&"; + break; + case ArithmeticOrLogicalOperator::BITWISE_OR: + operator_str = "|"; + break; + case ArithmeticOrLogicalOperator::BITWISE_XOR: + operator_str = "^"; + break; + case ArithmeticOrLogicalOperator::LEFT_SHIFT: + operator_str = "<<"; + break; + case ArithmeticOrLogicalOperator::RIGHT_SHIFT: + operator_str = ">>"; + break; + default: + operator_str = "invalid operator. wtf"; + break; + } + + std::string str ("ArithmeticOrLogicalExpr: "); + if (main_or_left_expr == nullptr || right_expr == nullptr) + { + str += "error. this is probably a parsing failure."; + } + else + { + str += main_or_left_expr->as_string () + " "; + str += operator_str + " "; + str += right_expr->as_string (); + } + + return str; +} + +std::string +CallExpr::as_string () const +{ + std::string str = "CallExpr: "; + + str += append_attributes (outer_attrs, OUTER); + + str += "\n Function expr: "; + str += function->as_string (); + + str += "\n Call params:"; + if (!has_params ()) + { + str += "none"; + } + else + { + for (const auto ¶m : params) + { + if (param == nullptr) + return "ERROR_MARK_STRING - call expr param is null"; + + str += "\n " + param->as_string (); + } + } + + return str; +} + +std::string +WhileLoopExpr::as_string () const +{ + std::string str = "WhileLoopExpr: "; + + str += append_attributes (outer_attrs, OUTER); + + str += "\n Label: "; + if (!has_loop_label ()) + str += "none"; + else + str += loop_label.as_string (); + + str += "\n Conditional expr: " + condition->as_string (); + + str += "\n Loop block: " + loop_block->as_string (); + + return str; +} + +std::string +WhileLetLoopExpr::as_string () const +{ + std::string str = "WhileLetLoopExpr: "; + + str += append_attributes (outer_attrs, OUTER); + + str += "\n Label: "; + if (!has_loop_label ()) + str += "none"; + else + str += loop_label.as_string (); + + str += "\n Match arm patterns: "; + if (match_arm_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &pattern : match_arm_patterns) + str += "\n " + pattern->as_string (); + } + + str += "\n Scrutinee expr: " + scrutinee->as_string (); + + str += "\n Loop block: " + loop_block->as_string (); + + return str; +} + +std::string +LoopExpr::as_string () const +{ + std::string str = "LoopExpr: (infinite loop)"; + + str += append_attributes (outer_attrs, OUTER); + + str += "\n Label: "; + if (!has_loop_label ()) + str += "none"; + else + str += loop_label.as_string (); + + str += "\n Loop block: " + loop_block->as_string (); + + return str; +} + +std::string +ArrayExpr::as_string () const +{ + std::string str = "ArrayExpr:"; + + str += append_attributes (outer_attrs, OUTER); + + // inner attributes + str += append_attributes (inner_attrs, INNER); + + str += "\n Array elems: "; + str += internal_elements->as_string (); + + return str; +} + +std::string +AwaitExpr::as_string () const +{ + // TODO: rewrite dump to allow non-literal exprs + return awaited_expr->as_string () + ".await"; +} + +std::string +BreakExpr::as_string () const +{ + // TODO: rewrite dump to allow outer attrs, non-literal exprs + std::string str ("break "); + + if (has_label ()) + str += label.as_string () + " "; + + if (has_break_expr ()) + str += break_expr->as_string (); + + return str; +} + +std::string +LoopLabel::as_string () const +{ + return label.as_string () + ": (label) "; +} + +std::string +MatchArm::as_string () const +{ + // outer attributes + std::string str = append_attributes (outer_attrs, OUTER); + + str += "\nPatterns: "; + if (match_arm_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &pattern : match_arm_patterns) + str += "\n " + pattern->as_string (); + } + + str += "\nGuard expr: "; + if (!has_match_arm_guard ()) + str += "none"; + else + str += guard_expr->as_string (); + + return str; +} + +std::string +MatchCase::as_string () const +{ + std::string str ("MatchCase: (match arm) "); + + str += "\n Match arm matcher: \n" + arm.as_string (); + str += "\n Expr: " + expr->as_string (); + + return str; +} + +std::string +MatchExpr::as_string () const +{ + std::string str ("MatchExpr:"); + + str += append_attributes (outer_attrs, OUTER); + + str += "\n Scrutinee expr: " + branch_value->as_string (); + + // inner attributes + str += append_attributes (inner_attrs, INNER); + + // match arms + str += "\n Match arms: "; + if (match_arms.empty ()) + { + str += "none"; + } + else + { + for (const auto &arm : match_arms) + str += "\n " + arm.as_string (); + } + + return str; +} + +std::string +TupleExpr::as_string () const +{ + std::string str ("TupleExpr:"); + + str += append_attributes (outer_attrs, OUTER); + + // inner attributes + str += append_attributes (inner_attrs, INNER); + + str += "\n Tuple elements: "; + if (tuple_elems.empty ()) + { + str += "none"; + } + else + { + for (const auto &elem : tuple_elems) + str += "\n " + elem->as_string (); + } + + return str; +} + +std::string +ExprStmtWithoutBlock::as_string () const +{ + std::string str ("ExprStmtWithoutBlock:\n"); + indent_spaces (enter); + str += indent_spaces (stay); + + if (expr == nullptr) + str += "none (this shouldn't happen and is probably an error)"; + else + str += expr->as_string (); + indent_spaces (out); + + return str; +} + +std::string +FunctionParam::as_string () const +{ + // TODO: rewrite dump to allow non-literal types + return param_name->as_string () + " : " + type->as_string (); +} + +std::string +FunctionQualifiers::as_string () const +{ + std::string str; + + switch (const_status) + { + case NONE: + // do nothing + break; + case CONST_FN: + str += "const "; + break; + case ASYNC_FN: + str += "async "; + break; + default: + return "ERROR_MARK_STRING: async-const status failure"; + } + + if (has_unsafe) + str += "unsafe "; + + if (has_extern) + { + str += "extern"; + if (extern_abi != "") + str += " \"" + extern_abi + "\""; + } + + return str; +} + +std::string +TraitBound::as_string () const +{ + std::string str ("TraitBound:"); + + str += "\n Has opening question mark: "; + if (opening_question_mark) + str += "true"; + else + str += "false"; + + str += "\n For lifetimes: "; + if (!has_for_lifetimes ()) + { + str += "none"; + } + else + { + for (const auto &lifetime : for_lifetimes) + str += "\n " + lifetime.as_string (); + } + + str += "\n Type path: " + type_path.as_string (); + + return str; +} + +std::string +MacroMatcher::as_string () const +{ + std::string str ("Macro matcher: "); + + str += "\n Delim type: "; + + switch (delim_type) + { + case PARENS: + str += "parentheses"; + break; + case SQUARE: + str += "square"; + break; + case CURLY: + str += "curly"; + break; + default: + return "ERROR_MARK_STRING - macro matcher delim"; + } + + str += "\n Matches: "; + + if (matches.empty ()) + { + str += "none"; + } + else + { + for (const auto &match : matches) + str += "\n " + match->as_string (); + } + + return str; +} + +std::string +LifetimeParam::as_string () const +{ + std::string str ("LifetimeParam: "); + + str += "\n Outer attribute: "; + if (!has_outer_attribute ()) + str += "none"; + else + str += outer_attr.as_string (); + + str += "\n Lifetime: " + lifetime.as_string (); + + str += "\n Lifetime bounds: "; + if (!has_lifetime_bounds ()) + { + str += "none"; + } + else + { + for (const auto &bound : lifetime_bounds) + str += "\n " + bound.as_string (); + } + + return str; +} + +std::string +ConstGenericParam::as_string () const +{ + std::string str ("ConstGenericParam: "); + str += "const " + name + ": " + type->as_string (); + + if (has_default_value ()) + str += " = " + get_default_value ().as_string (); + + return str; +} + +std::string +MacroMatchFragment::as_string () const +{ + return "$" + ident + ": " + frag_spec.as_string (); +} + +std::string +QualifiedPathInType::as_string () const +{ + /* TODO: this may need adjusting if segments (e.g. with functions) can't be + * literalised */ + std::string str = path_type.as_string (); + + for (const auto &segment : segments) + str += "::" + segment->as_string (); + + return str; +} + +std::string +MacroMatchRepetition::as_string () const +{ + std::string str ("Macro match repetition: "); + + str += "\n Matches: "; + if (matches.empty ()) + { + str += "none"; + } + else + { + for (const auto &match : matches) + str += "\n " + match->as_string (); + } + + str += "\n Sep: "; + if (!has_sep ()) + str += "none"; + else + str += sep->as_string (); + + str += "\n Op: "; + switch (op) + { + case ANY: + str += "*"; + break; + case ONE_OR_MORE: + str += "+"; + break; + case ZERO_OR_ONE: + str += "?"; + break; + case NONE: + str += "no op? shouldn't be allowed"; + break; + default: + return "ERROR_MARK_STRING - unknown op in macro match repetition"; + } + + return str; +} + +std::string +Lifetime::as_string () const +{ + if (is_error ()) + return "error lifetime"; + + switch (lifetime_type) + { + case NAMED: + return "'" + lifetime_name; + case STATIC: + return "'static"; + case WILDCARD: + return "'_"; + default: + return "ERROR-MARK-STRING: lifetime type failure"; + } +} + +std::string +TypePath::as_string () const +{ + /* TODO: this may need to be rewritten if a segment (e.g. function) can't be + * literalised */ + std::string str; + + if (has_opening_scope_resolution) + str = "::"; + + for (const auto &segment : segments) + str += segment->as_string () + "::"; + + // kinda hack - remove last 2 '::' characters + str.erase (str.length () - 2); + + return str; +} + +std::string +TypeParam::as_string () const +{ + std::string str ("TypeParam: "); + + str += "\n Outer attribute: "; + if (!has_outer_attribute ()) + str += "none"; + else + str += outer_attr.as_string (); + + str += "\n Identifier: " + type_representation; + + str += "\n Type param bounds: "; + if (!has_type_param_bounds ()) + { + str += "none"; + } + else + { + for (const auto &bound : type_param_bounds) + str += "\n " + bound->as_string (); + } + + str += "\n Type: "; + if (!has_type ()) + str += "none"; + else + str += type->as_string (); + + return str; +} + +SimplePath +PathPattern::convert_to_simple_path (bool with_opening_scope_resolution) const +{ + if (!has_segments ()) + return SimplePath::create_empty (); + + // create vector of reserved size (to minimise reallocations) + std::vector simple_segments; + simple_segments.reserve (segments.size ()); + + for (const auto &segment : segments) + { + // return empty path if doesn't meet simple path segment requirements + if (segment.is_error () || segment.has_generic_args () + || segment.as_string () == "Self") + return SimplePath::create_empty (); + + // create segment and add to vector + std::string segment_str = segment.as_string (); + simple_segments.push_back ( + SimplePathSegment (std::move (segment_str), segment.get_locus ())); + } + + // kind of a HACK to get locus depending on opening scope resolution + Location locus = Linemap::unknown_location (); + if (with_opening_scope_resolution) + locus = simple_segments[0].get_locus () - 2; // minus 2 chars for :: + else + locus = simple_segments[0].get_locus (); + // FIXME: this hack probably doesn't actually work + + return SimplePath (std::move (simple_segments), with_opening_scope_resolution, + locus); +} + +SimplePath +TypePath::as_simple_path () const +{ + if (segments.empty ()) + return SimplePath::create_empty (); + + // create vector of reserved size (to minimise reallocations) + std::vector simple_segments; + simple_segments.reserve (segments.size ()); + + for (const auto &segment : segments) + { + // return empty path if doesn't meet simple path segment requirements + if (segment == nullptr || segment->is_error () + || !segment->is_ident_only () || segment->as_string () == "Self") + return SimplePath::create_empty (); + + // create segment and add to vector + std::string segment_str = segment->as_string (); + simple_segments.push_back ( + SimplePathSegment (std::move (segment_str), segment->get_locus ())); + } + + return SimplePath (std::move (simple_segments), has_opening_scope_resolution, + locus); +} + +std::string +PathExprSegment::as_string () const +{ + // TODO: rewrite dump to work with non-literalisable types + std::string ident_str = segment_name.as_string (); + if (has_generic_args ()) + ident_str += "::<" + generic_args.as_string () + ">"; + + return ident_str; +} + +std::string +GenericArgs::as_string () const +{ + std::string args; + + // lifetime args + if (!lifetime_args.empty ()) + { + auto i = lifetime_args.begin (); + auto e = lifetime_args.end (); + + for (; i != e; i++) + { + args += (*i).as_string (); + if (e != i + 1) + args += ", "; + } + } + + // type args + if (!generic_args.empty ()) + { + auto i = generic_args.begin (); + auto e = generic_args.end (); + + for (; i != e; i++) + { + args += (*i).as_string (); + if (e != i + 1) + args += ", "; + } + } + + // binding args + if (!binding_args.empty ()) + { + auto i = binding_args.begin (); + auto e = binding_args.end (); + + for (; i != e; i++) + { + args += (*i).as_string (); + if (e != i + 1) + args += ", "; + } + } + + return args; +} + +std::string +GenericArgsBinding::as_string () const +{ + // TODO: rewrite to work with non-literalisable types + return identifier + " = " + type->as_string (); +} + +std::string +ForLoopExpr::as_string () const +{ + std::string str = "ForLoopExpr: "; + + str += append_attributes (outer_attrs, OUTER); + + str += "\n Label: "; + if (!has_loop_label ()) + str += "none"; + else + str += loop_label.as_string (); + + str += "\n Pattern: " + pattern->as_string (); + + str += "\n Iterator expr: " + iterator_expr->as_string (); + + str += "\n Loop block: " + loop_block->as_string (); + + return str; +} + +std::string +RangePattern::as_string () const +{ + // TODO: maybe rewrite to work with non-linearisable bounds + if (has_ellipsis_syntax) + return lower->as_string () + "..." + upper->as_string (); + else + return lower->as_string () + "..=" + upper->as_string (); +} + +std::string +RangePatternBoundLiteral::as_string () const +{ + std::string str; + + if (has_minus) + str += "-"; + + str += literal.as_string (); + + return str; +} + +std::string +SlicePattern::as_string () const +{ + std::string str ("SlicePattern: "); + + for (const auto &pattern : items) + str += "\n " + pattern->as_string (); + + return str; +} + +std::string +TuplePatternItemsMultiple::as_string () const +{ + std::string str; + + for (const auto &pattern : patterns) + str += "\n " + pattern->as_string (); + + return str; +} + +std::string +TuplePatternItemsRanged::as_string () const +{ + std::string str; + + str += "\n Lower patterns: "; + if (lower_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &lower : lower_patterns) + str += "\n " + lower->as_string (); + } + + str += "\n Upper patterns: "; + if (upper_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &upper : upper_patterns) + str += "\n " + upper->as_string (); + } + + return str; +} + +std::string +TuplePattern::as_string () const +{ + return "TuplePattern: " + items->as_string (); +} + +std::string +StructPatternField::as_string () const +{ + // outer attributes + std::string str = append_attributes (outer_attrs, OUTER); + + return str; +} + +std::string +StructPatternFieldIdent::as_string () const +{ + std::string str = StructPatternField::as_string (); + + str += "\n"; + + if (has_ref) + str += "ref "; + + if (has_mut) + str += "mut "; + + str += ident; + + return str; +} + +std::string +StructPatternFieldTuplePat::as_string () const +{ + // TODO: maybe rewrite to work with non-linearisable patterns + std::string str = StructPatternField::as_string (); + + str += "\n"; + + str += std::to_string (index) + " : " + tuple_pattern->as_string (); + + return str; +} + +std::string +StructPatternFieldIdentPat::as_string () const +{ + // TODO: maybe rewrite to work with non-linearisable patterns + std::string str = StructPatternField::as_string (); + + str += "\n"; + + str += ident + " : " + ident_pattern->as_string (); + + return str; +} + +std::string +StructPatternElements::as_string () const +{ + std::string str ("\n Fields: "); + + if (!has_struct_pattern_fields ()) + { + str += "none"; + } + else + { + for (const auto &field : fields) + str += "\n " + field->as_string (); + } + + str += "\n Etc: "; + if (has_struct_pattern_etc) + str += "true"; + else + str += "false"; + + return str; +} + +std::string +StructPattern::as_string () const +{ + std::string str ("StructPattern: \n Path: "); + + str += path.as_string (); + + str += "\n Struct pattern elems: "; + if (!has_struct_pattern_elems ()) + str += "none"; + else + str += elems.as_string (); + + return str; +} + +std::string +LiteralPattern::as_string () const +{ + return lit.as_string (); +} + +std::string +ReferencePattern::as_string () const +{ + // TODO: maybe rewrite to work with non-linearisable patterns + std::string str ("&"); + + if (has_two_amps) + str += "&"; + + if (is_mut) + str += "mut "; + + str += pattern->as_string (); + + return str; +} + +std::string +IdentifierPattern::as_string () const +{ + // TODO: maybe rewrite to work with non-linearisable patterns + std::string str; + + if (is_ref) + str += "ref "; + + if (is_mut) + str += "mut "; + + str += variable_ident; + + if (has_pattern_to_bind ()) + str += " @ " + to_bind->as_string (); + + return str; +} + +std::string +TupleStructItemsNoRange::as_string () const +{ + std::string str; + + for (const auto &pattern : patterns) + str += "\n " + pattern->as_string (); + + return str; +} + +std::string +TupleStructItemsRange::as_string () const +{ + std::string str ("\n Lower patterns: "); + + if (lower_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &lower : lower_patterns) + str += "\n " + lower->as_string (); + } + + str += "\n Upper patterns: "; + if (upper_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &upper : upper_patterns) + str += "\n " + upper->as_string (); + } + + return str; +} + +std::string +TupleStructPattern::as_string () const +{ + std::string str ("TupleStructPattern: \n Path: "); + + str += path.as_string (); + + str += "\n Tuple struct items: " + items->as_string (); + + return str; +} + +std::string +LetStmt::as_string () const +{ + // TODO: rewrite to work with non-linearisable types and exprs + std::string str = append_attributes (outer_attrs, OUTER); + + str += "\n" + indent_spaces (stay) + "let " + variables_pattern->as_string (); + + if (has_type ()) + str += " : " + type->as_string (); + + if (has_init_expr ()) + str += " = " + init_expr->as_string (); + + return str; +} + +// hopefully definition here will prevent circular dependency issue +TraitBound * +TypePath::to_trait_bound (bool in_parens) const +{ + return new TraitBound (TypePath (*this), get_locus (), in_parens); +} + +std::string +InferredType::as_string () const +{ + return "_ (inferred)"; +} + +std::string +TypeCastExpr::as_string () const +{ + // TODO: rewrite to work with non-linearisable exprs and types + return main_or_left_expr->as_string () + " as " + + type_to_convert_to->as_string (); +} + +std::string +ImplTraitType::as_string () const +{ + std::string str ("ImplTraitType: \n TypeParamBounds: "); + + if (type_param_bounds.empty ()) + { + str += "none"; + } + else + { + for (const auto &bound : type_param_bounds) + str += "\n " + bound->as_string (); + } + + return str; +} + +std::string +ReferenceType::as_string () const +{ + // TODO: rewrite to work with non-linearisable types + std::string str ("&"); + + if (has_lifetime ()) + str += lifetime.as_string () + " "; + + if (has_mut) + str += "mut "; + + str += type->as_string (); + + return str; +} + +std::string +RawPointerType::as_string () const +{ + // TODO: rewrite to work with non-linearisable types + std::string str ("*"); + + switch (pointer_type) + { + case MUT: + str += "mut "; + break; + case CONST: + str += "const "; + break; + default: + return "ERROR_MARK_STRING - unknown pointer type in raw pointer type"; + } + + str += type->as_string (); + + return str; +} + +std::string +TraitObjectType::as_string () const +{ + std::string str ("TraitObjectType: \n Has dyn dispatch: "); + + if (has_dyn) + str += "true"; + else + str += "false"; + + str += "\n TypeParamBounds: "; + if (type_param_bounds.empty ()) + { + str += "none"; + } + else + { + for (const auto &bound : type_param_bounds) + str += "\n " + bound->as_string (); + } + + return str; +} + +std::string +BareFunctionType::as_string () const +{ + std::string str ("BareFunctionType: \n For lifetimes: "); + + if (!has_for_lifetimes ()) + { + str += "none"; + } + else + { + for (const auto &for_lifetime : for_lifetimes) + str += "\n " + for_lifetime.as_string (); + } + + str += "\n Qualifiers: " + function_qualifiers.as_string (); + + str += "\n Params: "; + if (params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : params) + str += "\n " + param.as_string (); + } + + str += "\n Is variadic: "; + if (is_variadic) + str += "true"; + else + str += "false"; + + str += "\n Return type: "; + if (!has_return_type ()) + str += "none (void)"; + else + str += return_type->as_string (); + + return str; +} + +std::string +ImplTraitTypeOneBound::as_string () const +{ + std::string str ("ImplTraitTypeOneBound: \n TraitBound: "); + + return str + trait_bound.as_string (); +} + +std::string +TypePathSegmentGeneric::as_string () const +{ + // TODO: rewrite to work with non-linearisable types + return TypePathSegment::as_string () + "<" + generic_args.as_string () + ">"; +} + +std::string +TraitObjectTypeOneBound::as_string () const +{ + std::string str ("TraitObjectTypeOneBound: \n Has dyn dispatch: "); + + if (has_dyn) + str += "true"; + else + str += "false"; + + str += "\n TraitBound: " + trait_bound.as_string (); + + return str; +} + +std::string +TypePathFunction::as_string () const +{ + // TODO: rewrite to work with non-linearisable types + std::string str ("("); + + if (has_inputs ()) + { + auto i = inputs.begin (); + auto e = inputs.end (); + + for (; i != e; i++) + { + str += (*i)->as_string (); + if (e != i + 1) + str += ", "; + } + } + + str += ")"; + + if (has_return_type ()) + str += " -> " + return_type->as_string (); + + return str; +} + +std::string +TypePathSegmentFunction::as_string () const +{ + // TODO: rewrite to work with non-linearisable types + return TypePathSegment::as_string () + function_path.as_string (); +} + +std::string +ArrayType::as_string () const +{ + // TODO: rewrite to work with non-linearisable types and exprs + return "[" + elem_type->as_string () + "; " + size->as_string () + "]"; +} + +std::string +SliceType::as_string () const +{ + // TODO: rewrite to work with non-linearisable types + return "[" + elem_type->as_string () + "]"; +} + +std::string +TupleType::as_string () const +{ + // TODO: rewrite to work with non-linearisable types + std::string str ("("); + + if (!is_unit_type ()) + { + auto i = elems.begin (); + auto e = elems.end (); + + for (; i != e; i++) + { + str += (*i)->as_string (); + if (e != i + 1) + str += ", "; + } + } + + str += ")"; + + return str; +} + +std::string +StructExpr::as_string () const +{ + std::string str = append_attributes (outer_attrs, OUTER); + indent_spaces (enter); + str += "\n" + indent_spaces (stay) + "StructExpr:"; + indent_spaces (enter); + str += "\n" + indent_spaces (stay) + "PathInExpr:\n"; + str += indent_spaces (stay) + struct_name.as_string (); + indent_spaces (out); + indent_spaces (out); + return str; +} + +std::string +StructExprStruct::as_string () const +{ + // TODO: doesn't this require data from StructExpr? + std::string str ("StructExprStruct (or subclass): "); + + str += "\n Path: " + get_struct_name ().as_string (); + + // inner attributes + str += append_attributes (inner_attrs, INNER); + + return str; +} + +std::string +StructBase::as_string () const +{ + if (base_struct != nullptr) + return base_struct->as_string (); + else + return "ERROR_MARK_STRING - invalid struct base had as string applied"; +} + +std::string +StructExprFieldWithVal::as_string () const +{ + // used to get value string + return value->as_string (); +} + +std::string +StructExprFieldIdentifierValue::as_string () const +{ + // TODO: rewrite to work with non-linearisable exprs + return field_name + " : " + StructExprFieldWithVal::as_string (); +} + +std::string +StructExprFieldIndexValue::as_string () const +{ + // TODO: rewrite to work with non-linearisable exprs + return std::to_string (index) + " : " + StructExprFieldWithVal::as_string (); +} + +std::string +StructExprStructFields::as_string () const +{ + std::string str = StructExprStruct::as_string (); + + str += "\n Fields: "; + if (fields.empty ()) + { + str += "none"; + } + else + { + for (const auto &field : fields) + str += "\n " + field->as_string (); + } + + str += "\n Struct base: "; + if (!has_struct_base ()) + str += "none"; + else + str += struct_base.as_string (); + + return str; +} + +std::string +EnumItem::as_string () const +{ + std::string str = VisItem::as_string (); + str += variant_name; + + return str; +} + +std::string +EnumItemTuple::as_string () const +{ + std::string str = EnumItem::as_string (); + + // add tuple opening parens + str += "("; + + // tuple fields + if (has_tuple_fields ()) + { + auto i = tuple_fields.begin (); + auto e = tuple_fields.end (); + + for (; i != e; i++) + { + str += (*i).as_string (); + if (e != i + 1) + str += ", "; + } + } + + // add tuple closing parens + str += ")"; + + return str; +} + +std::string +TupleField::as_string () const +{ + // TODO: rewrite to work with non-linearisable exprs + + // outer attributes + std::string str = append_attributes (outer_attrs, OUTER); + + if (has_visibility ()) + str += "\n" + visibility.as_string (); + + str += " " + field_type->as_string (); + + return str; +} + +std::string +EnumItemStruct::as_string () const +{ + std::string str = EnumItem::as_string (); + + // add struct opening parens + str += "{"; + + // tuple fields + if (has_struct_fields ()) + { + auto i = struct_fields.begin (); + auto e = struct_fields.end (); + + for (; i != e; i++) + { + str += (*i).as_string (); + if (e != i + 1) + str += ", "; + } + } + + // add struct closing parens + str += "}"; + + return str; +} + +std::string +StructField::as_string () const +{ + // TODO: rewrite to work with non-linearisable exprs + // outer attributes + std::string str = append_attributes (outer_attrs, OUTER); + + if (has_visibility ()) + str += "\n" + visibility.as_string (); + + str += " " + field_name + " : " + field_type->as_string (); + + return str; +} + +std::string +EnumItemDiscriminant::as_string () const +{ + // TODO: rewrite to work with non-linearisable exprs + std::string str = EnumItem::as_string (); + + // add equal and expression + str += " = " + expression->as_string (); + + return str; +} + +std::string +ExternalStaticItem::as_string () const +{ + // outer attributes + std::string str = append_attributes (outer_attrs, OUTER); + + // start visibility on new line and with a space + str += "\n" + visibility.as_string () + " "; + + str += "static "; + + if (has_mut) + str += "mut "; + + // add name + str += item_name; + + // add type on new line + str += "\n Type: " + item_type->as_string (); + + return str; +} + +std::string +ExternalFunctionItem::as_string () const +{ + // outer attributes + std::string str = append_attributes (outer_attrs, OUTER); + + // start visibility on new line and with a space + str += "\n" + visibility.as_string () + " "; + + str += "fn "; + + // add name + str += item_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + { + // DEBUG: null pointer check + if (param == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "generic param in external function item."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string (); + } + } + + // function params + str += "\n Function params: "; + if (function_params.empty () && !has_variadics) + { + str += "none"; + } + else + { + for (const auto ¶m : function_params) + str += "\n " + param.as_string (); + + if (has_variadics) + { + str += "\n variadic outer attrs: "; + if (has_variadic_outer_attrs ()) + { + for (const auto &attr : variadic_outer_attrs) + str += "\n " + attr.as_string (); + } + else + { + str += "none"; + } + str += "\n ... (variadic)"; + } + } + + // add type on new line + str += "\n (return) Type: " + + (has_return_type () ? return_type->as_string () : "()"); + + // where clause + str += "\n Where clause: "; + if (has_where_clause ()) + str += where_clause.as_string (); + else + str += "none"; + + return str; +} + +std::string +NamedFunctionParam::as_string () const +{ + std::string str = append_attributes (outer_attrs, OUTER); + + str += "\n" + name; + + str += "\n Type: " + param_type->as_string (); + + return str; +} + +std::string +TraitItemFunc::as_string () const +{ + std::string str = append_attributes (outer_attrs, OUTER); + + str += "\n" + decl.as_string (); + + str += "\n Definition (block expr): "; + if (has_definition ()) + str += block_expr->as_string (); + else + str += "none"; + + return str; +} + +std::string +TraitFunctionDecl::as_string () const +{ + std::string str = qualifiers.as_string () + "fn " + function_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + { + // DEBUG: null pointer check + if (param == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "generic param in trait function decl."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string (); + } + } + + str += "\n Function params: "; + if (has_params ()) + { + for (const auto ¶m : function_params) + str += "\n " + param.as_string (); + } + else + { + str += "none"; + } + + str += "\n Return type: "; + if (has_return_type ()) + str += return_type->as_string (); + else + str += "none (void)"; + + str += "\n Where clause: "; + if (has_where_clause ()) + str += where_clause.as_string (); + else + str += "none"; + + return str; +} + +std::string +TraitItemMethod::as_string () const +{ + std::string str = append_attributes (outer_attrs, OUTER); + + str += "\n" + decl.as_string (); + + str += "\n Definition (block expr): "; + if (has_definition ()) + str += block_expr->as_string (); + else + str += "none"; + + return str; +} + +std::string +TraitMethodDecl::as_string () const +{ + std::string str = qualifiers.as_string () + "fn " + function_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty ()) + { + str += "none"; + } + else + { + for (const auto ¶m : generic_params) + { + // DEBUG: null pointer check + if (param == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "generic param in trait function decl."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string (); + } + } + + str += "\n Self param: " + self_param.as_string (); + + str += "\n Function params: "; + if (has_params ()) + { + for (const auto ¶m : function_params) + str += "\n " + param.as_string (); + } + else + { + str += "none"; + } + + str += "\n Return type: "; + if (has_return_type ()) + str += return_type->as_string (); + else + str += "none (void)"; + + str += "\n Where clause: "; + if (has_where_clause ()) + str += where_clause.as_string (); + else + str += "none"; + + return str; +} + +std::string +TraitItemConst::as_string () const +{ + // TODO: rewrite to work with non-linearisable exprs + std::string str = append_attributes (outer_attrs, OUTER); + + str += "\nconst " + name + " : " + type->as_string (); + + if (has_expression ()) + str += " = " + expr->as_string (); + + return str; +} + +std::string +TraitItemType::as_string () const +{ + std::string str = append_attributes (outer_attrs, OUTER); + + str += "\ntype " + name; + + str += "\n Type param bounds: "; + if (!has_type_param_bounds ()) + { + str += "none"; + } + else + { + for (const auto &bound : type_param_bounds) + { + // DEBUG: null pointer check + if (bound == nullptr) + { + rust_debug ( + "something really terrible has gone wrong - null pointer " + "type param bound in trait item type."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + bound->as_string (); + } + } + + return str; +} + +std::string +SelfParam::as_string () const +{ + // TODO: rewrite to allow non-linearisable types + if (is_error ()) + { + return "error"; + } + else + { + if (has_type ()) + { + // type (i.e. not ref, no lifetime) + std::string str; + + if (is_mut) + str += "mut "; + + str += "self : "; + + str += type->as_string (); + + return str; + } + else if (has_lifetime ()) + { + // ref and lifetime + std::string str = "&" + lifetime.as_string () + " "; + + if (is_mut) + str += "mut "; + + str += "self"; + + return str; + } + else if (has_ref) + { + // ref with no lifetime + std::string str = "&"; + + if (is_mut) + str += " mut "; + + str += "self"; + + return str; + } + else + { + // no ref, no type + std::string str; + + if (is_mut) + str += "mut "; + + str += "self"; + + return str; + } + } +} + +std::string +ArrayElemsCopied::as_string () const +{ + // TODO: rewrite to allow non-linearisable exprs + return elem_to_copy->as_string () + "; " + num_copies->as_string (); +} + +std::string +LifetimeWhereClauseItem::as_string () const +{ + std::string str ("Lifetime: "); + + str += lifetime.as_string (); + + str += "\nLifetime bounds: "; + + for (const auto &bound : lifetime_bounds) + str += "\n " + bound.as_string (); + + return str; +} + +std::string +TypeBoundWhereClauseItem::as_string () const +{ + std::string str ("For lifetimes: "); + + if (!has_for_lifetimes ()) + { + str += "none"; + } + else + { + for (const auto &for_lifetime : for_lifetimes) + str += "\n " + for_lifetime.as_string (); + } + + str += "\nType: " + bound_type->as_string (); + + str += "\nType param bounds bounds: "; + + for (const auto &bound : type_param_bounds) + { + // debug null pointer check + if (bound == nullptr) + return "NULL_POINTER_MARK - type param bounds"; + + str += "\n " + bound->as_string (); + } + + return str; +} + +std::string +ArrayElemsValues::as_string () const +{ + std::string str; + + for (const auto &expr : values) + { + // DEBUG: null pointer check + if (expr == nullptr) + { + rust_debug ("something really terrible has gone wrong - null pointer " + "expr in array elems values."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + expr->as_string (); + } + + return str; +} + +std::string +MaybeNamedParam::as_string () const +{ + // TODO: rewrite to allow using non-linearisable types in dump + std::string str; + + switch (param_kind) + { + case UNNAMED: + break; + case IDENTIFIER: + str = name + " : "; + break; + case WILDCARD: + str = "_ : "; + break; + default: + return "ERROR_MARK_STRING - maybe named param unrecognised param kind"; + } + + str += param_type->as_string (); + + return str; +} + +MetaItemInner::~MetaItemInner () = default; + +std::unique_ptr +MetaItemInner::to_meta_name_value_str () const +{ + if (is_key_value_pair ()) + { + auto converted_item = static_cast (this); + return converted_item->to_meta_name_value_str (); + } + // TODO actually parse foo = bar + return nullptr; +} + +std::string +MetaItemSeq::as_string () const +{ + std::string path_str = path.as_string () + "("; + + auto i = seq.begin (); + auto e = seq.end (); + + for (; i != e; i++) + { + path_str += (*i)->as_string (); + if (e != i + 1) + path_str += ", "; + } + + return path_str + ")"; +} + +std::string +MetaListPaths::as_string () const +{ + std::string str = ident + "("; + + auto i = paths.begin (); + auto e = paths.end (); + + for (; i != e; i++) + { + str += (*i).as_string (); + if (e != i + 1) + str += ", "; + } + + return str + ")"; +} + +std::string +MetaListNameValueStr::as_string () const +{ + std::string str = ident + "("; + + auto i = strs.begin (); + auto e = strs.end (); + + for (; i != e; i++) + { + str += (*i).as_string (); + if (e != i + 1) + str += ", "; + } + + return str + ")"; +} + +std::string +AttrInputMetaItemContainer::as_string () const +{ + std::string str = "("; + + auto i = items.begin (); + auto e = items.end (); + + for (; i != e; i++) + { + str += (*i)->as_string (); + if (e != i + 1) + str += ", "; + } + + return str + ")"; +} + +/* Override that calls the function recursively on all items contained within + * the module. */ +void +Module::add_crate_name (std::vector &names) const +{ + /* TODO: test whether module has been 'cfg'-ed out to determine whether to + * exclude it from search */ + + for (const auto &item : items) + item->add_crate_name (names); +} + +static bool +file_exists (const std::string path) +{ + // Simply check if the file exists + // FIXME: This does not work on Windows + return access (path.c_str (), F_OK) != -1; +} + +static std::string +filename_from_path_attribute (std::vector &outer_attrs) +{ + // An out-of-line module cannot have inner attributes. Additionally, the + // default name is specified as `""` so that the caller can detect the case + // of "no path given" and use the default path logic (`name.rs` or + // `name/mod.rs`). + return extract_module_path ({}, outer_attrs, ""); +} + +void +Module::process_file_path () +{ + rust_assert (kind == Module::ModuleKind::UNLOADED); + rust_assert (module_file.empty ()); + + // This corresponds to the path of the file 'including' the module. So the + // file that contains the 'mod ;' directive + std::string including_fname (outer_filename); + + std::string expected_file_path = module_name + ".rs"; + std::string expected_dir_path = "mod.rs"; + + auto dir_slash_pos = including_fname.rfind (file_separator); + std::string current_directory_name; + + // If we haven't found a file_separator, then we have to look for files in the + // current directory ('.') + if (dir_slash_pos == std::string::npos) + current_directory_name = std::string (".") + file_separator; + else + current_directory_name + = including_fname.substr (0, dir_slash_pos) + file_separator; + + // Handle inline module declarations adding path components. + for (auto const &name : module_scope) + { + current_directory_name.append (name); + current_directory_name.append (file_separator); + } + + auto path_string = filename_from_path_attribute (get_outer_attrs ()); + if (!path_string.empty ()) + { + module_file = current_directory_name + path_string; + return; + } + + // FIXME: We also have to search for + // //.rs In rustc, this is done via + // the concept of `DirOwnernship`, which is based on whether or not the + // current file is titled `mod.rs`. + + // First, we search for /.rs + std::string file_mod_path = current_directory_name + expected_file_path; + bool file_mod_found = file_exists (file_mod_path); + + // Then, search for //mod.rs + std::string dir_mod_path + = current_directory_name + module_name + file_separator + expected_dir_path; + bool dir_mod_found = file_exists (dir_mod_path); + + bool multiple_candidates_found = file_mod_found && dir_mod_found; + bool no_candidates_found = !file_mod_found && !dir_mod_found; + + if (multiple_candidates_found) + rust_error_at (locus, + "two candidates found for module %s: %s.rs and %s%smod.rs", + module_name.c_str (), module_name.c_str (), + module_name.c_str (), file_separator); + + if (no_candidates_found) + rust_error_at (locus, "no candidate found for module %s", + module_name.c_str ()); + + if (no_candidates_found || multiple_candidates_found) + return; + + module_file = std::move (file_mod_found ? file_mod_path : dir_mod_path); +} + +void +Module::load_items () +{ + process_file_path (); + + // We will already have errored out appropriately in the process_file_path () + // method + if (module_file.empty ()) + return; + + RAIIFile file_wrap (module_file.c_str ()); + Linemap *linemap = Session::get_instance ().linemap; + if (!file_wrap.ok ()) + { + rust_error_at (get_locus (), "cannot open module file %s: %m", + module_file.c_str ()); + return; + } + + rust_debug ("Attempting to parse file %s", module_file.c_str ()); + + Lexer lex (module_file.c_str (), std::move (file_wrap), linemap); + Parser parser (lex); + + // we need to parse any possible inner attributes for this module + inner_attrs = parser.parse_inner_attributes (); + auto parsed_items = parser.parse_items (); + for (const auto &error : parser.get_errors ()) + error.emit_error (); + + items = std::move (parsed_items); + kind = ModuleKind::LOADED; +} + +void +Attribute::parse_attr_to_meta_item () +{ + // only parse if has attribute input and not already parsed + if (!has_attr_input () || is_parsed_to_meta_item ()) + return; + + auto res = attr_input->parse_to_meta_item (); + std::unique_ptr converted_input (res); + + if (converted_input != nullptr) + attr_input = std::move (converted_input); +} + +AttrInputMetaItemContainer * +DelimTokenTree::parse_to_meta_item () const +{ + // must have token trees + if (token_trees.empty ()) + return nullptr; + + /* assume top-level delim token tree in attribute - convert all nested ones + * to token stream */ + std::vector> token_stream = to_token_stream (); + + AttributeParser parser (std::move (token_stream)); + std::vector> meta_items ( + parser.parse_meta_item_seq ()); + + return new AttrInputMetaItemContainer (std::move (meta_items)); +} + +std::unique_ptr +AttributeParser::parse_meta_item_inner () +{ + // if first tok not identifier, not a "special" case one + if (peek_token ()->get_id () != IDENTIFIER) + { + switch (peek_token ()->get_id ()) + { + case CHAR_LITERAL: + case STRING_LITERAL: + case BYTE_CHAR_LITERAL: + case BYTE_STRING_LITERAL: + case INT_LITERAL: + case FLOAT_LITERAL: + case TRUE_LITERAL: + case FALSE_LITERAL: + return parse_meta_item_lit (); + + case SUPER: + case SELF: + case CRATE: + case DOLLAR_SIGN: + case SCOPE_RESOLUTION: + return parse_path_meta_item (); + + default: + rust_error_at (peek_token ()->get_locus (), + "unrecognised token '%s' in meta item", + get_token_description (peek_token ()->get_id ())); + return nullptr; + } + } + + // else, check for path + if (peek_token (1)->get_id () == SCOPE_RESOLUTION) + { + // path + return parse_path_meta_item (); + } + + auto ident = peek_token ()->as_string (); + auto ident_locus = peek_token ()->get_locus (); + + if (is_end_meta_item_tok (peek_token (1)->get_id ())) + { + // meta word syntax + skip_token (); + return std::unique_ptr (new MetaWord (ident, ident_locus)); + } + + if (peek_token (1)->get_id () == EQUAL) + { + // maybe meta name value str syntax - check next 2 tokens + if (peek_token (2)->get_id () == STRING_LITERAL + && is_end_meta_item_tok (peek_token (3)->get_id ())) + { + // meta name value str syntax + auto &value_tok = peek_token (2); + auto value = value_tok->as_string (); + auto locus = value_tok->get_locus (); + + skip_token (2); + + // remove the quotes from the string value + std::string raw_value = unquote_string (std::move (value)); + + return std::unique_ptr ( + new MetaNameValueStr (ident, ident_locus, std::move (raw_value), + locus)); + } + else + { + // just interpret as path-based meta item + return parse_path_meta_item (); + } + } + + if (peek_token (1)->get_id () != LEFT_PAREN) + { + rust_error_at (peek_token (1)->get_locus (), + "unexpected token '%s' after identifier in attribute", + get_token_description (peek_token (1)->get_id ())); + return nullptr; + } + + // is it one of those special cases like not? + if (peek_token ()->get_id () == IDENTIFIER) + { + return parse_path_meta_item (); + } + + auto meta_items = parse_meta_item_seq (); + + // pass for meta name value str + std::vector meta_name_value_str_items; + for (const auto &item : meta_items) + { + std::unique_ptr converted_item + = item->to_meta_name_value_str (); + if (converted_item == nullptr) + { + meta_name_value_str_items.clear (); + break; + } + meta_name_value_str_items.push_back (std::move (*converted_item)); + } + // if valid, return this + if (!meta_name_value_str_items.empty ()) + { + return std::unique_ptr ( + new MetaListNameValueStr (ident, ident_locus, + std::move (meta_name_value_str_items))); + } + + // // pass for meta list idents + // std::vector ident_items; + // for (const auto &item : meta_items) + // { + // std::unique_ptr converted_ident (item->to_ident_item ()); + // if (converted_ident == nullptr) + // { + // ident_items.clear (); + // break; + // } + // ident_items.push_back (std::move (*converted_ident)); + // } + // // if valid return this + // if (!ident_items.empty ()) + // { + // return std::unique_ptr ( + // new MetaListIdents (std::move (ident), std::move (ident_items))); + // } + // // as currently no meta list ident, currently no path. may change in future + + // pass for meta list paths + std::vector path_items; + for (const auto &item : meta_items) + { + SimplePath converted_path (item->to_path_item ()); + if (converted_path.is_empty ()) + { + path_items.clear (); + break; + } + path_items.push_back (std::move (converted_path)); + } + if (!path_items.empty ()) + { + return std::unique_ptr ( + new MetaListPaths (ident, ident_locus, std::move (path_items))); + } + + rust_error_at (Linemap::unknown_location (), + "failed to parse any meta item inner"); + return nullptr; +} + +bool +AttributeParser::is_end_meta_item_tok (TokenId id) const +{ + return id == COMMA || id == RIGHT_PAREN; +} + +std::unique_ptr +AttributeParser::parse_path_meta_item () +{ + SimplePath path = parse_simple_path (); + if (path.is_empty ()) + { + rust_error_at (peek_token ()->get_locus (), + "failed to parse simple path in attribute"); + return nullptr; + } + + switch (peek_token ()->get_id ()) + { + case LEFT_PAREN: { + std::vector> meta_items + = parse_meta_item_seq (); + + return std::unique_ptr ( + new MetaItemSeq (std::move (path), std::move (meta_items))); + } + case EQUAL: { + skip_token (); + + Location locus = peek_token ()->get_locus (); + Literal lit = parse_literal (); + if (lit.is_error ()) + { + rust_error_at (peek_token ()->get_locus (), + "failed to parse literal in attribute"); + return nullptr; + } + LiteralExpr expr (std::move (lit), {}, locus); + // stream_pos++; + /* shouldn't be required anymore due to parsing literal actually + * skipping the token */ + return std::unique_ptr ( + new MetaItemPathLit (std::move (path), std::move (expr))); + } + case COMMA: + // just simple path + return std::unique_ptr ( + new MetaItemPath (std::move (path))); + default: + rust_error_at (peek_token ()->get_locus (), + "unrecognised token '%s' in meta item", + get_token_description (peek_token ()->get_id ())); + return nullptr; + } +} + +/* Parses a parenthesised sequence of meta item inners. Parentheses are + * required here. */ +std::vector> +AttributeParser::parse_meta_item_seq () +{ + int vec_length = token_stream.size (); + std::vector> meta_items; + + if (peek_token ()->get_id () != LEFT_PAREN) + { + rust_error_at (peek_token ()->get_locus (), + "missing left paren in delim token tree"); + return {}; + } + skip_token (); + + while (stream_pos < vec_length && peek_token ()->get_id () != RIGHT_PAREN) + { + std::unique_ptr inner = parse_meta_item_inner (); + if (inner == nullptr) + { + rust_error_at (peek_token ()->get_locus (), + "failed to parse inner meta item in attribute"); + return {}; + } + meta_items.push_back (std::move (inner)); + + if (peek_token ()->get_id () != COMMA) + break; + + skip_token (); + } + + if (peek_token ()->get_id () != RIGHT_PAREN) + { + rust_error_at (peek_token ()->get_locus (), + "missing right paren in delim token tree"); + return {}; + } + skip_token (); + + return meta_items; +} + +/* Collects any nested token trees into a flat token stream, suitable for + * parsing. */ +std::vector> +DelimTokenTree::to_token_stream () const +{ + std::vector> tokens; + for (const auto &tree : token_trees) + { + std::vector> stream = tree->to_token_stream (); + + tokens.insert (tokens.end (), std::make_move_iterator (stream.begin ()), + std::make_move_iterator (stream.end ())); + } + + tokens.shrink_to_fit (); + return tokens; +} + +Literal +AttributeParser::parse_literal () +{ + const std::unique_ptr &tok = peek_token (); + switch (tok->get_id ()) + { + case CHAR_LITERAL: + skip_token (); + return Literal (tok->as_string (), Literal::CHAR, tok->get_type_hint ()); + case STRING_LITERAL: + skip_token (); + return Literal (tok->as_string (), Literal::STRING, + tok->get_type_hint ()); + case BYTE_CHAR_LITERAL: + skip_token (); + return Literal (tok->as_string (), Literal::BYTE, tok->get_type_hint ()); + case BYTE_STRING_LITERAL: + skip_token (); + return Literal (tok->as_string (), Literal::BYTE_STRING, + tok->get_type_hint ()); + case INT_LITERAL: + skip_token (); + return Literal (tok->as_string (), Literal::INT, tok->get_type_hint ()); + case FLOAT_LITERAL: + skip_token (); + return Literal (tok->as_string (), Literal::FLOAT, tok->get_type_hint ()); + case TRUE_LITERAL: + skip_token (); + return Literal ("true", Literal::BOOL, tok->get_type_hint ()); + case FALSE_LITERAL: + skip_token (); + return Literal ("false", Literal::BOOL, tok->get_type_hint ()); + default: + rust_error_at (tok->get_locus (), "expected literal - found '%s'", + get_token_description (tok->get_id ())); + return Literal::create_error (); + } +} + +SimplePath +AttributeParser::parse_simple_path () +{ + bool has_opening_scope_res = false; + if (peek_token ()->get_id () == SCOPE_RESOLUTION) + { + has_opening_scope_res = true; + skip_token (); + } + + std::vector segments; + + SimplePathSegment segment = parse_simple_path_segment (); + if (segment.is_error ()) + { + rust_error_at ( + peek_token ()->get_locus (), + "failed to parse simple path segment in attribute simple path"); + return SimplePath::create_empty (); + } + segments.push_back (std::move (segment)); + + while (peek_token ()->get_id () == SCOPE_RESOLUTION) + { + skip_token (); + + SimplePathSegment segment = parse_simple_path_segment (); + if (segment.is_error ()) + { + rust_error_at ( + peek_token ()->get_locus (), + "failed to parse simple path segment in attribute simple path"); + return SimplePath::create_empty (); + } + segments.push_back (std::move (segment)); + } + segments.shrink_to_fit (); + + return SimplePath (std::move (segments), has_opening_scope_res); +} + +SimplePathSegment +AttributeParser::parse_simple_path_segment () +{ + const std::unique_ptr &tok = peek_token (); + switch (tok->get_id ()) + { + case IDENTIFIER: + skip_token (); + return SimplePathSegment (tok->as_string (), tok->get_locus ()); + case SUPER: + skip_token (); + return SimplePathSegment ("super", tok->get_locus ()); + case SELF: + skip_token (); + return SimplePathSegment ("self", tok->get_locus ()); + case CRATE: + skip_token (); + return SimplePathSegment ("crate", tok->get_locus ()); + case DOLLAR_SIGN: + if (peek_token (1)->get_id () == CRATE) + { + skip_token (1); + return SimplePathSegment ("$crate", tok->get_locus ()); + } + gcc_fallthrough (); + default: + rust_error_at (tok->get_locus (), + "unexpected token '%s' in simple path segment", + get_token_description (tok->get_id ())); + return SimplePathSegment::create_error (); + } +} + +std::unique_ptr +AttributeParser::parse_meta_item_lit () +{ + Location locus = peek_token ()->get_locus (); + LiteralExpr lit_expr (parse_literal (), {}, locus); + return std::unique_ptr ( + new MetaItemLitExpr (std::move (lit_expr))); +} + +bool +AttrInputMetaItemContainer::check_cfg_predicate (const Session &session) const +{ + if (items.empty ()) + return false; + + for (const auto &inner_item : items) + { + if (!inner_item->check_cfg_predicate (session)) + return false; + } + + return true; +} + +bool +MetaItemLitExpr::check_cfg_predicate (const Session &) const +{ + /* as far as I can tell, a literal expr can never be a valid cfg body, so + * false */ + return false; +} + +bool +MetaListNameValueStr::check_cfg_predicate (const Session &session) const +{ + if (ident == "all") + { + for (const auto &str : strs) + { + if (!str.check_cfg_predicate (session)) + return false; + } + return true; + } + else if (ident == "any") + { + for (const auto &str : strs) + { + if (str.check_cfg_predicate (session)) + return true; + } + return false; + } + else if (ident == "not") + { + if (strs.size () != 1) + { + /* HACK: convert vector platform-dependent size_type to string to + * use in printf */ + rust_error_at (Linemap::unknown_location (), + "cfg predicate could not be checked for " + "MetaListNameValueStr with ident of " + "'not' because there are '%s' elements, not '1'", + std::to_string (strs.size ()).c_str ()); + return false; + } + + return !strs[0].check_cfg_predicate (session); + } + else + { + rust_error_at (Linemap::unknown_location (), + "cfg predicate could not be checked for " + "MetaListNameValueStr with ident of " + "'%s' - ident must be 'all' or 'any'", + ident.c_str ()); + return false; + } +} + +bool +MetaListPaths::check_cfg_predicate (const Session &session) const +{ + if (ident == "all") + { + for (const auto &path : paths) + { + if (!check_path_exists_in_cfg (session, path)) + return false; + } + return true; + } + else if (ident == "any") + { + for (const auto &path : paths) + { + if (check_path_exists_in_cfg (session, path)) + return true; + } + return false; + } + else if (ident == "not") + { + if (paths.size () != 1) + { + // HACK: convert vector platform-dependent size_type to string to + // use in printf + rust_error_at (Linemap::unknown_location (), + "cfg predicate could not be checked for MetaListPaths " + "with ident of 'not' " + "because there are '%s' elements, not '1'", + std::to_string (paths.size ()).c_str ()); + return false; + } + + return !check_path_exists_in_cfg (session, paths[0]); + } + else + { + rust_error_at (Linemap::unknown_location (), + "cfg predicate could not be checked for " + "MetaListNameValueStr with ident of " + "'%s' - ident must be 'all' or 'any'", + ident.c_str ()); + return false; + } +} + +bool +MetaListPaths::check_path_exists_in_cfg (const Session &session, + const SimplePath &path) const +{ + return session.options.target_data.has_key (path.as_string ()); +} + +bool +MetaItemSeq::check_cfg_predicate (const Session &session) const +{ + if (path.as_string () == "all") + { + for (const auto &item : seq) + { + if (!item->check_cfg_predicate (session)) + return false; + } + return true; + } + else if (path.as_string () == "any") + { + for (const auto &item : seq) + { + if (item->check_cfg_predicate (session)) + return true; + } + return false; + } + else if (path.as_string () == "not") + { + if (seq.size () != 1) + { + /* HACK: convert vector platform-dependent size_type to string to + * use in printf */ + rust_error_at (Linemap::unknown_location (), + "cfg predicate could not be checked for MetaItemSeq " + "with ident of 'not' " + "because there are '%s' elements, not '1'", + std::to_string (seq.size ()).c_str ()); + return false; + } + + return !seq[0]->check_cfg_predicate (session); + } + else + { + rust_error_at ( + Linemap::unknown_location (), + "cfg predicate could not be checked for MetaItemSeq with path of " + "'%s' - path must be 'all' or 'any'", + path.as_string ().c_str ()); + return false; + } +} + +bool +MetaWord::check_cfg_predicate (const Session &session) const +{ + return session.options.target_data.has_key (ident); +} + +bool +MetaItemPath::check_cfg_predicate (const Session &session) const +{ + /* Strictly speaking, this should always be false, but maybe do check + * relating to SimplePath being identifier. Currently, it would return true + * if path as identifier existed, and if the path in string form existed + * (though this shouldn't occur). */ + return session.options.target_data.has_key (path.as_string ()); +} + +bool +MetaNameValueStr::check_cfg_predicate (const Session &session) const +{ + // DEBUG + rust_debug ( + "checked key-value pair for cfg: '%s', '%s' - is%s in target data", + ident.c_str (), str.c_str (), + session.options.target_data.has_key_value_pair (ident, str) ? "" : " not"); + + return session.options.target_data.has_key_value_pair (ident, str); +} + +bool +MetaItemPathLit::check_cfg_predicate (const Session &session) const +{ + return session.options.target_data.has_key_value_pair (path.as_string (), + lit.as_string ()); +} + +std::vector> +Token::to_token_stream () const +{ + /* initialisation list doesn't work as it needs copy constructor, so have to + * do this */ + std::vector> dummy_vector; + dummy_vector.reserve (1); + dummy_vector.push_back (std::unique_ptr (clone_token_impl ())); + return dummy_vector; +} + +Attribute +MetaNameValueStr::to_attribute () const +{ + LiteralExpr lit_expr (str, Literal::LitType::STRING, + PrimitiveCoreType::CORETYPE_UNKNOWN, {}, str_locus); + // FIXME: What location do we put here? Is the literal above supposed to have + // an empty location as well? + // Should MetaNameValueStr keep a location? + return Attribute (SimplePath::from_str (ident, ident_locus), + std::unique_ptr ( + new AttrInputLiteral (std::move (lit_expr)))); +} + +Attribute +MetaItemPath::to_attribute () const +{ + return Attribute (path, nullptr); +} + +Attribute +MetaItemSeq::to_attribute () const +{ + std::vector> new_seq; + new_seq.reserve (seq.size ()); + for (const auto &e : seq) + new_seq.push_back (e->clone_meta_item_inner ()); + + std::unique_ptr new_seq_container ( + new AttrInputMetaItemContainer (std::move (new_seq))); + return Attribute (path, std::move (new_seq_container)); +} + +Attribute +MetaWord::to_attribute () const +{ + return Attribute (SimplePath::from_str (ident, ident_locus), nullptr); +} + +Attribute +MetaListPaths::to_attribute () const +{ + /* probably one of the most annoying conversions - have to lose specificity by + * turning it into just AttrInputMetaItemContainer (i.e. paths-only nature is + * no longer known). If conversions back are required, might have to do a + * "check all are paths" pass or something. */ + + std::vector> new_seq; + new_seq.reserve (paths.size ()); + for (const auto &e : paths) + new_seq.push_back (std::unique_ptr (new MetaItemPath (e))); + + std::unique_ptr new_seq_container ( + new AttrInputMetaItemContainer (std::move (new_seq))); + return Attribute (SimplePath::from_str (ident, ident_locus), + std::move (new_seq_container)); +} + +Attribute +MetaListNameValueStr::to_attribute () const +{ + std::vector> new_seq; + new_seq.reserve (strs.size ()); + for (const auto &e : strs) + new_seq.push_back ( + std::unique_ptr (new MetaNameValueStr (e))); + + std::unique_ptr new_seq_container ( + new AttrInputMetaItemContainer (std::move (new_seq))); + return Attribute (SimplePath::from_str (ident, ident_locus), + std::move (new_seq_container)); +} + +Attribute +MetaItemPathLit::to_attribute () const +{ + return Attribute (path, std::unique_ptr ( + new AttrInputLiteral (lit))); +} + +std::vector +AttrInputMetaItemContainer::separate_cfg_attrs () const +{ + rust_assert (!items.empty ()); + + if (items.size () == 1) + return {}; + + std::vector attrs; + attrs.reserve (items.size () - 1); + + for (auto it = items.begin () + 1; it != items.end (); ++it) + { + Attribute attr = (*it)->to_attribute (); + if (attr.is_empty ()) + { + /* TODO should this be an error that causes us to chuck out + * everything? */ + continue; + } + attrs.push_back (std::move (attr)); + } + + attrs.shrink_to_fit (); + return attrs; +} + +bool +Attribute::check_cfg_predicate (const Session &session) const +{ + /* assume that cfg predicate actually can exist, i.e. attribute has cfg or + * cfg_attr path */ + if (!has_attr_input () + || (path.as_string () != "cfg" && path.as_string () != "cfg_attr")) + { + // DEBUG message + rust_debug ( + "tried to check cfg predicate on attr that either has no input " + "or invalid path. attr: '%s'", + as_string ().c_str ()); + + return false; + } + + // assume that it has already been parsed + if (!is_parsed_to_meta_item ()) + return false; + + return attr_input->check_cfg_predicate (session); +} + +std::vector +Attribute::separate_cfg_attrs () const +{ + if (!has_attr_input () || path.as_string () != "cfg_attr") + return {}; + + // assume that it has already been parsed + if (!is_parsed_to_meta_item ()) + return {}; + + return attr_input->separate_cfg_attrs (); +} + +bool +Attribute::is_parsed_to_meta_item () const +{ + return has_attr_input () && attr_input->is_meta_item (); +} + +/* Visitor implementations - these are short but inlining can't happen anyway + * due to virtual functions and I didn't want to make the ast header includes + * any longer than they already are. */ + +void +Token::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +DelimTokenTree::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +IdentifierExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +Lifetime::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +LifetimeParam::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ConstGenericParam::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +PathInExpression::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TypePathSegment::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TypePathSegmentGeneric::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TypePathSegmentFunction::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TypePath::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +QualifiedPathInExpression::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +QualifiedPathInType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +LiteralExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +AttrInputLiteral::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MetaItemLitExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MetaItemPathLit::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +BorrowExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +DereferenceExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ErrorPropagationExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +NegationExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ArithmeticOrLogicalExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ComparisonExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +LazyBooleanExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TypeCastExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +AssignmentExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +CompoundAssignmentExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +GroupedExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ArrayElemsValues::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ArrayElemsCopied::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ArrayExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ArrayIndexExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TupleExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TupleIndexExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructExprStruct::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructExprFieldIdentifier::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructExprFieldIdentifierValue::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructExprFieldIndexValue::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructExprStructFields::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructExprStructBase::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +CallExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MethodCallExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +FieldAccessExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ClosureExprInner::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +BlockExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ClosureExprInnerTyped::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ContinueExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +BreakExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RangeFromToExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RangeFromExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RangeToExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RangeFullExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RangeFromToInclExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RangeToInclExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ReturnExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +UnsafeBlockExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +LoopExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +WhileLoopExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +WhileLetLoopExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ForLoopExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +IfExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +IfExprConseqElse::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +IfExprConseqIf::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +IfExprConseqIfLet::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +IfLetExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +IfLetExprConseqElse::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +IfLetExprConseqIf::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +IfLetExprConseqIfLet::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MatchExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +AwaitExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +AsyncBlockExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TypeParam::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +LifetimeWhereClauseItem::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TypeBoundWhereClauseItem::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +Method::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +Module::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ExternCrate::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +UseTreeGlob::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +UseTreeList::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +UseTreeRebind::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +UseDeclaration::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +Function::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TypeAlias::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructStruct::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TupleStruct::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +EnumItem::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +EnumItemTuple::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +EnumItemStruct::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +EnumItemDiscriminant::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +Enum::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +Union::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ConstantItem::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StaticItem::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TraitItemFunc::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TraitItemMethod::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TraitItemConst::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TraitItemType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +Trait::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +InherentImpl::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TraitImpl::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ExternalStaticItem::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ExternalFunctionItem::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ExternBlock::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MacroMatchFragment::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MacroMatchRepetition::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MacroMatcher::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MacroRulesDefinition::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MacroInvocation::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +LiteralPattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +IdentifierPattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +WildcardPattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RangePatternBoundLiteral::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RangePatternBoundPath::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RangePatternBoundQualPath::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RangePattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ReferencePattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructPatternFieldTuplePat::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructPatternFieldIdentPat::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructPatternFieldIdent::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +StructPattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TupleStructItemsNoRange::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TupleStructItemsRange::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TupleStructPattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TuplePatternItemsMultiple::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TuplePatternItemsRanged::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TuplePattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +GroupedPattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +SlicePattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +EmptyStmt::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +LetStmt::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ExprStmtWithoutBlock::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ExprStmtWithBlock::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TraitBound::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ImplTraitType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TraitObjectType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ParenthesisedType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ImplTraitTypeOneBound::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TraitObjectTypeOneBound::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +TupleType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +NeverType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +RawPointerType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ReferenceType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ArrayType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +SliceType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +InferredType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +BareFunctionType::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MetaItemSeq::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MetaItemPath::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MetaListPaths::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MetaNameValueStr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MetaListNameValueStr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +AttrInputMetaItemContainer::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +MetaWord::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +GenericArg +GenericArg::disambiguate_to_const () const +{ + rust_assert (get_kind () == Kind::Either); + + // FIXME: is it fine to have no outer attributes? + return GenericArg::create_const ( + std::unique_ptr (new IdentifierExpr (path, {}, locus))); +} + +GenericArg +GenericArg::disambiguate_to_type () const +{ + rust_assert (get_kind () == Kind::Either); + + auto segment = std::unique_ptr ( + new TypePathSegment (path, false, locus)); + auto segments = std::vector> (); + segments.emplace_back (std::move (segment)); + + return GenericArg::create_type ( + std::unique_ptr (new TypePath (std::move (segments), locus))); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-ast-full.h b/gcc/rust/ast/rust-ast-full.h new file mode 100644 index 00000000000..5ab136c61b6 --- /dev/null +++ b/gcc/rust/ast/rust-ast-full.h @@ -0,0 +1,31 @@ +// Copyright (C) 2020-2022 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 +// . + +#ifndef RUST_AST_FULL_H +#define RUST_AST_FULL_H +// Use as a fast way of including all aspects of the AST (i.e. all headers) +#include "rust-ast.h" +#include "rust-expr.h" +#include "rust-item.h" +#include "rust-path.h" +#include "rust-pattern.h" +#include "rust-stmt.h" +#include "rust-type.h" +#include "rust-macro.h" + +#endif diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h new file mode 100644 index 00000000000..461a2460f8f --- /dev/null +++ b/gcc/rust/ast/rust-ast.h @@ -0,0 +1,2007 @@ +// Copyright (C) 2020-2022 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 +// . + +#ifndef RUST_AST_BASE_H +#define RUST_AST_BASE_H +// Base for AST used in gccrs, basically required by all specific ast things + +#include "rust-system.h" +#include "rust-hir-map.h" +#include "rust-token.h" +#include "rust-location.h" + +namespace Rust { +// TODO: remove typedefs and make actual types for these +typedef std::string Identifier; +typedef int TupleIndex; +struct Session; + +namespace AST { +// foward decl: ast visitor +class ASTVisitor; +using AttrVec = std::vector; + +// The available kinds of AST Nodes +enum Kind +{ + UNKNOWN, + MACRO_RULES_DEFINITION, + MACRO_INVOCATION, +}; + +// Abstract base class for all AST elements +class Node +{ +public: + /** + * Get the kind of Node this is. This is used to differentiate various AST + * elements with very little overhead when extracting the derived type through + * static casting is not necessary. + */ + // FIXME: Mark this as `= 0` in the future to make sure every node implements + // it + virtual Kind get_ast_kind () const { return Kind::UNKNOWN; } +}; + +// Delimiter types - used in macros and whatever. +enum DelimType +{ + PARENS, + SQUARE, + CURLY +}; + +// forward decl for use in token tree method +class Token; + +// A tree of tokens (or a single token) - abstract base class +class TokenTree +{ +public: + virtual ~TokenTree () {} + + // Unique pointer custom clone function + std::unique_ptr clone_token_tree () const + { + return std::unique_ptr (clone_token_tree_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + /* Converts token tree to a flat token stream. Tokens must be pointer to avoid + * mutual dependency with Token. */ + virtual std::vector > to_token_stream () const = 0; + +protected: + // pure virtual clone implementation + virtual TokenTree *clone_token_tree_impl () const = 0; +}; + +// Abstract base class for a macro match +class MacroMatch +{ +public: + enum MacroMatchType + { + Fragment, + Repetition, + Matcher, + Tok + }; + + virtual ~MacroMatch () {} + + virtual std::string as_string () const = 0; + virtual Location get_match_locus () const = 0; + + // Unique pointer custom clone function + std::unique_ptr clone_macro_match () const + { + return std::unique_ptr (clone_macro_match_impl ()); + } + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual MacroMatchType get_macro_match_type () const = 0; + +protected: + // pure virtual clone implementation + virtual MacroMatch *clone_macro_match_impl () const = 0; +}; + +// A token is a kind of token tree (except delimiter tokens) +class Token : public TokenTree, public MacroMatch +{ + // A token is a kind of token tree (except delimiter tokens) + // A token is a kind of MacroMatch (except $ and delimiter tokens) +#if 0 + // TODO: improve member variables - current ones are the same as lexer token + // Token kind. + TokenId token_id; + // Token location. + Location locus; + // Associated text (if any) of token. + std::string str; + // Token type hint (if any). + PrimitiveCoreType type_hint; +#endif + + const_TokenPtr tok_ref; + + /* new idea: wrapper around const_TokenPtr used for heterogeneuous storage in + * token trees. rather than convert back and forth when parsing macros, just + * wrap it. */ + +public: + // Unique pointer custom clone function + std::unique_ptr clone_token () const + { + return std::unique_ptr (clone_token_impl ()); + } + +#if 0 + /* constructor from general text - avoid using if lexer const_TokenPtr is + * available */ + Token (TokenId token_id, Location locus, std::string str, + PrimitiveCoreType type_hint) + : token_id (token_id), locus (locus), str (std::move (str)), + type_hint (type_hint) + {} +#endif + // not doable with new implementation - will have to make a const_TokenPtr + + // Constructor from lexer const_TokenPtr +#if 0 + /* TODO: find workaround for std::string being nullptr - probably have to + * introduce new method in lexer Token, or maybe make conversion method + * there */ + Token (const_TokenPtr lexer_token_ptr) + : token_id (lexer_token_ptr->get_id ()), + locus (lexer_token_ptr->get_locus ()), str (""), + type_hint (lexer_token_ptr->get_type_hint ()) + { + // FIXME: change to "should have str" later? + if (lexer_token_ptr->has_str ()) + { + str = lexer_token_ptr->get_str (); + + // DEBUG + rust_debug ("ast token created with str '%s'", str.c_str ()); + } + else + { + // FIXME: is this returning correct thing? + str = lexer_token_ptr->get_token_description (); + + // DEBUG + rust_debug ("ast token created with string '%s'", str.c_str ()); + } + + // DEBUG + if (lexer_token_ptr->should_have_str () && !lexer_token_ptr->has_str ()) + { + rust_debug ( + "BAD: for token '%s', should have string but does not!", + lexer_token_ptr->get_token_description ()); + } + } +#endif + Token (const_TokenPtr lexer_tok_ptr) : tok_ref (std::move (lexer_tok_ptr)) {} + + bool is_string_lit () const + { + switch (get_id ()) + { + case STRING_LITERAL: + case BYTE_STRING_LITERAL: + return true; + default: + return false; + } + } + + std::string as_string () const override; + Location get_match_locus () const override { return tok_ref->get_locus (); }; + + void accept_vis (ASTVisitor &vis) override; + + // Return copy of itself but in token stream form. + std::vector > to_token_stream () const override; + + TokenId get_id () const { return tok_ref->get_id (); } + const std::string &get_str () const { return tok_ref->get_str (); } + + Location get_locus () const { return tok_ref->get_locus (); } + + PrimitiveCoreType get_type_hint () const { return tok_ref->get_type_hint (); } + + // Get a new token pointer copy. + const_TokenPtr get_tok_ptr () const { return tok_ref; } + + MacroMatchType get_macro_match_type () const override + { + return MacroMatchType::Tok; + } + +protected: + // No virtual for now as not polymorphic but can be in future + /*virtual*/ Token *clone_token_impl () const { return new Token (*this); } + + /* Use covariance to implement clone function as returning this object rather + * than base */ + Token *clone_token_tree_impl () const final override + { + return clone_token_impl (); + } + + /* Use covariance to implement clone function as returning this object rather + * than base */ + Token *clone_macro_match_impl () const final override + { + return clone_token_impl (); + } +}; + +// A literal - value with a type. Used in LiteralExpr and LiteralPattern. +struct Literal +{ +public: + enum LitType + { + CHAR, + STRING, + BYTE, + BYTE_STRING, + INT, + FLOAT, + BOOL, + ERROR + }; + +private: + /* TODO: maybe make subclasses of each type of literal with their typed values + * (or generics) */ + std::string value_as_string; + LitType type; + PrimitiveCoreType type_hint; + +public: + std::string as_string () const { return value_as_string; } + + LitType get_lit_type () const { return type; } + + PrimitiveCoreType get_type_hint () const { return type_hint; } + + Literal (std::string value_as_string, LitType type, + PrimitiveCoreType type_hint) + : value_as_string (std::move (value_as_string)), type (type), + type_hint (type_hint) + {} + + static Literal create_error () + { + return Literal ("", ERROR, PrimitiveCoreType::CORETYPE_UNKNOWN); + } + + // Returns whether literal is in an invalid state. + bool is_error () const { return type == ERROR; } +}; + +/* Forward decl - definition moved to rust-expr.h as it requires LiteralExpr to + * be defined */ +class AttrInputLiteral; + +/* TODO: move applicable stuff into here or just don't include it because + * nothing uses it A segment of a path (maybe) */ +class PathSegment +{ +public: + virtual ~PathSegment () {} + + virtual std::string as_string () const = 0; + + // TODO: add visitor here? +}; + +// A segment of a simple path without generic or type arguments +class SimplePathSegment : public PathSegment +{ + std::string segment_name; + Location locus; + NodeId node_id; + + // only allow identifiers, "super", "self", "crate", or "$crate" +public: + // TODO: put checks in constructor to enforce this rule? + SimplePathSegment (std::string segment_name, Location locus) + : segment_name (std::move (segment_name)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + /* Returns whether simple path segment is in an invalid state (currently, if + * empty). */ + bool is_error () const { return segment_name.empty (); } + + // Creates an error SimplePathSegment + static SimplePathSegment create_error () + { + return SimplePathSegment (std::string (""), Location ()); + } + + std::string as_string () const override; + + Location get_locus () const { return locus; } + NodeId get_node_id () const { return node_id; } + const std::string &get_segment_name () const { return segment_name; } + bool is_super_path_seg () const + { + return as_string ().compare ("super") == 0; + } + bool is_crate_path_seg () const + { + return as_string ().compare ("crate") == 0; + } + bool is_lower_self () const { return as_string ().compare ("self") == 0; } + bool is_big_self () const { return as_string ().compare ("Self") == 0; } +}; + +// A simple path without generic or type arguments +class SimplePath +{ + bool has_opening_scope_resolution; + std::vector segments; + Location locus; + NodeId node_id; + +public: + // Constructor + SimplePath (std::vector path_segments, + bool has_opening_scope_resolution = false, + Location locus = Location ()) + : has_opening_scope_resolution (has_opening_scope_resolution), + segments (std::move (path_segments)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + // Creates an empty SimplePath. + static SimplePath create_empty () + { + return SimplePath (std::vector ()); + } + + // Returns whether the SimplePath is empty, i.e. has path segments. + bool is_empty () const { return segments.empty (); } + + std::string as_string () const; + + Location get_locus () const { return locus; } + NodeId get_node_id () const { return node_id; } + + // does this need visitor if not polymorphic? probably not + + // path-to-string comparison operator + bool operator== (const std::string &rhs) const + { + return !has_opening_scope_resolution && segments.size () == 1 + && segments[0].as_string () == rhs; + } + + /* Creates a single-segment SimplePath from a string. This will not check to + * ensure that this is a valid identifier in path, so be careful. Also, this + * will have no location data. + * TODO have checks? */ + static SimplePath from_str (std::string str, Location locus) + { + std::vector single_segments + = {AST::SimplePathSegment (std::move (str), locus)}; + return SimplePath (std::move (single_segments)); + } + + const std::vector &get_segments () const + { + return segments; + } + + std::vector &get_segments () { return segments; } +}; + +// path-to-string inverse comparison operator +inline bool +operator!= (const SimplePath &lhs, const std::string &rhs) +{ + return !(lhs == rhs); +} + +// forward decl for Attribute +class AttrInput; + +// aka Attr +// Attribute AST representation +struct Attribute +{ +private: + SimplePath path; + + // bool has_attr_input; + std::unique_ptr attr_input; + + Location locus; + + // TODO: maybe a variable storing whether attr input is parsed or not + +public: + // Returns whether Attribute has AttrInput + bool has_attr_input () const { return attr_input != nullptr; } + + // Constructor has pointer AttrInput for polymorphism reasons + Attribute (SimplePath path, std::unique_ptr input, + Location locus = Location ()) + : path (std::move (path)), attr_input (std::move (input)), locus (locus) + {} + + // default destructor + ~Attribute () = default; + + // no point in being defined inline as requires virtual call anyway + Attribute (const Attribute &other); + + // no point in being defined inline as requires virtual call anyway + Attribute &operator= (const Attribute &other); + + // default move semantics + Attribute (Attribute &&other) = default; + Attribute &operator= (Attribute &&other) = default; + + // Unique pointer custom clone function + std::unique_ptr clone_attribute () const + { + return std::unique_ptr (clone_attribute_impl ()); + } + + // Creates an empty attribute (which is invalid) + static Attribute create_empty () + { + return Attribute (SimplePath::create_empty (), nullptr); + } + + // Returns whether the attribute is considered an "empty" attribute. + bool is_empty () const { return attr_input == nullptr && path.is_empty (); } + + Location get_locus () const { return locus; } + + AttrInput &get_attr_input () const { return *attr_input; } + + /* e.g.: + #![crate_type = "lib"] + #[test] + #[cfg(target_os = "linux")] + #[allow(non_camel_case_types)] + #![allow(unused_variables)] + */ + + // Full built-in attribute list: + /* cfg + * cfg_attr + * test + * ignore + * should_panic + * derive + * macro_export + * macro_use + * proc_macro + * proc_macro_derive + * proc_macro_attribute + * allow + * warn + * deny + * forbid + * deprecated + * must_use + * link + * link_name + * no_link + * repr + * crate_type + * no_main + * export_name + * link_section + * no_mangle + * used + * crate_name + * inline + * cold + * no_builtins + * target_feature + * doc + * no_std + * no_implicit_prelude + * path + * recursion_limit + * type_length_limit + * panic_handler + * global_allocator + * windows_subsystem + * feature */ + + std::string as_string () const; + + // no visitor pattern as not currently polymorphic + + const SimplePath &get_path () const { return path; } + SimplePath &get_path () { return path; } + + // Call to parse attribute body to meta item syntax. + void parse_attr_to_meta_item (); + + /* Determines whether cfg predicate is true and item with attribute should not + * be stripped. Attribute body must already be parsed to meta item. */ + bool check_cfg_predicate (const Session &session) const; + + // Returns whether body has been parsed to meta item form or not. + bool is_parsed_to_meta_item () const; + + /* Returns any attributes generated from cfg_attr attributes. Attribute body + * must already be parsed to meta item. */ + std::vector separate_cfg_attrs () const; + +protected: + // not virtual as currently no subclasses of Attribute, but could be in future + /*virtual*/ Attribute *clone_attribute_impl () const + { + return new Attribute (*this); + } +}; + +// Attribute body - abstract base class +class AttrInput +{ +public: + enum AttrInputType + { + LITERAL, + META_ITEM, + TOKEN_TREE, + }; + + virtual ~AttrInput () {} + + // Unique pointer custom clone function + std::unique_ptr clone_attr_input () const + { + return std::unique_ptr (clone_attr_input_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual bool check_cfg_predicate (const Session &session) const = 0; + + // Parse attribute input to meta item, if possible + virtual AttrInput *parse_to_meta_item () const { return nullptr; } + + virtual std::vector separate_cfg_attrs () const { return {}; } + + // Returns whether attr input has been parsed to meta item syntax. + virtual bool is_meta_item () const = 0; + + virtual AttrInputType get_attr_input_type () const = 0; + +protected: + // pure virtual clone implementation + virtual AttrInput *clone_attr_input_impl () const = 0; +}; + +// Forward decl - defined in rust-macro.h +class MetaNameValueStr; + +// abstract base meta item inner class +class MetaItemInner +{ +protected: + // pure virtual as MetaItemInner + virtual MetaItemInner *clone_meta_item_inner_impl () const = 0; + +public: + // Unique pointer custom clone function + std::unique_ptr clone_meta_item_inner () const + { + return std::unique_ptr (clone_meta_item_inner_impl ()); + } + + virtual ~MetaItemInner (); + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + /* HACK: used to simplify parsing - creates a copy of that type, or returns + * null */ + virtual std::unique_ptr to_meta_name_value_str () const; + + // HACK: used to simplify parsing - same thing + virtual SimplePath to_path_item () const + { + return SimplePath::create_empty (); + } + + virtual Attribute to_attribute () const { return Attribute::create_empty (); } + + virtual bool check_cfg_predicate (const Session &session) const = 0; + + virtual bool is_key_value_pair () const { return false; } +}; + +// Container used to store MetaItems as AttrInput (bridge-ish kinda thing) +class AttrInputMetaItemContainer : public AttrInput +{ + std::vector > items; + +public: + AttrInputMetaItemContainer ( + std::vector > items) + : items (std::move (items)) + {} + + // copy constructor with vector clone + AttrInputMetaItemContainer (const AttrInputMetaItemContainer &other) + { + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_meta_item_inner ()); + } + + // copy assignment operator with vector clone + AttrInputMetaItemContainer & + operator= (const AttrInputMetaItemContainer &other) + { + AttrInput::operator= (other); + + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_meta_item_inner ()); + + return *this; + } + + // default move constructors + AttrInputMetaItemContainer (AttrInputMetaItemContainer &&other) = default; + AttrInputMetaItemContainer &operator= (AttrInputMetaItemContainer &&other) + = default; + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + bool check_cfg_predicate (const Session &session) const override; + + AttrInputType get_attr_input_type () const final override + { + return AttrInput::AttrInputType::META_ITEM; + } + + // Clones this object. + std::unique_ptr + clone_attr_input_meta_item_container () const + { + return std::unique_ptr ( + clone_attr_input_meta_item_container_impl ()); + } + + std::vector separate_cfg_attrs () const override; + + bool is_meta_item () const override { return true; } + + // TODO: this mutable getter seems dodgy + std::vector > &get_items () { return items; } + const std::vector > &get_items () const + { + return items; + } + +protected: + // Use covariance to implement clone function as returning this type + AttrInputMetaItemContainer *clone_attr_input_impl () const final override + { + return clone_attr_input_meta_item_container_impl (); + } + + AttrInputMetaItemContainer *clone_attr_input_meta_item_container_impl () const + { + return new AttrInputMetaItemContainer (*this); + } +}; + +// A token tree with delimiters +class DelimTokenTree : public TokenTree, public AttrInput +{ + DelimType delim_type; + std::vector > token_trees; + Location locus; + +protected: + DelimTokenTree *clone_delim_tok_tree_impl () const + { + return new DelimTokenTree (*this); + } + + /* Use covariance to implement clone function as returning a DelimTokenTree + * object */ + DelimTokenTree *clone_attr_input_impl () const final override + { + return clone_delim_tok_tree_impl (); + } + + /* Use covariance to implement clone function as returning a DelimTokenTree + * object */ + DelimTokenTree *clone_token_tree_impl () const final override + { + return clone_delim_tok_tree_impl (); + } + +public: + DelimTokenTree (DelimType delim_type, + std::vector > token_trees + = std::vector > (), + Location locus = Location ()) + : delim_type (delim_type), token_trees (std::move (token_trees)), + locus (locus) + {} + + // Copy constructor with vector clone + DelimTokenTree (DelimTokenTree const &other) + : delim_type (other.delim_type), locus (other.locus) + { + token_trees.reserve (other.token_trees.size ()); + for (const auto &e : other.token_trees) + token_trees.push_back (e->clone_token_tree ()); + } + + // overloaded assignment operator with vector clone + DelimTokenTree &operator= (DelimTokenTree const &other) + { + delim_type = other.delim_type; + locus = other.locus; + + token_trees.reserve (other.token_trees.size ()); + for (const auto &e : other.token_trees) + token_trees.push_back (e->clone_token_tree ()); + + return *this; + } + + // move constructors + DelimTokenTree (DelimTokenTree &&other) = default; + DelimTokenTree &operator= (DelimTokenTree &&other) = default; + + static DelimTokenTree create_empty () { return DelimTokenTree (PARENS); } + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + bool check_cfg_predicate (const Session &) const override + { + // this should never be called - should be converted first + rust_assert (false); + return false; + } + + AttrInputMetaItemContainer *parse_to_meta_item () const override; + + std::vector > to_token_stream () const override; + + std::unique_ptr clone_delim_token_tree () const + { + return std::unique_ptr (clone_delim_tok_tree_impl ()); + } + + bool is_meta_item () const override { return false; } + + AttrInputType get_attr_input_type () const final override + { + return AttrInput::AttrInputType::TOKEN_TREE; + } + + std::vector > &get_token_trees () + { + return token_trees; + } + + DelimType get_delim_type () const { return delim_type; } +}; + +/* Forward decl - definition moved to rust-expr.h as it requires LiteralExpr to + * be defined */ +class AttrInputLiteral; + +// abstract base meta item class +class MetaItem : public MetaItemInner +{ +}; + +// Forward decl - defined in rust-expr.h +class MetaItemLitExpr; + +// Forward decl - defined in rust-expr.h +class MetaItemPathLit; + +// Forward decl - defined in rust-macro.h +class MetaItemPath; + +// Forward decl - defined in rust-macro.h +class MetaItemSeq; + +// Forward decl - defined in rust-macro.h +class MetaWord; + +// Forward decl - defined in rust-macro.h +class MetaListPaths; + +// Forward decl - defined in rust-macro.h +class MetaListNameValueStr; + +/* Base statement abstract class. Note that most "statements" are not allowed in + * top-level module scope - only a subclass of statements called "items" are. */ +class Stmt : public Node +{ +public: + // Unique pointer custom clone function + std::unique_ptr clone_stmt () const + { + return std::unique_ptr (clone_stmt_impl ()); + } + + virtual ~Stmt () {} + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual Location get_locus () const = 0; + + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; + NodeId get_node_id () const { return node_id; } + + virtual bool is_item () const = 0; + +protected: + Stmt () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} + + // Clone function implementation as pure virtual method + virtual Stmt *clone_stmt_impl () const = 0; + + NodeId node_id; +}; + +// Rust "item" AST node (declaration of top-level/module-level allowed stuff) +class Item : public Stmt +{ +public: + // Unique pointer custom clone function + std::unique_ptr clone_item () const + { + return std::unique_ptr (clone_item_impl ()); + } + + /* Adds crate names to the vector passed by reference, if it can + * (polymorphism). TODO: remove, unused. */ + virtual void + add_crate_name (std::vector &names ATTRIBUTE_UNUSED) const + {} + + // FIXME: ARTHUR: Is it okay to have removed that final? Is it *required* + // behavior that we have items that can also be expressions? + bool is_item () const override { return true; } + +protected: + // Clone function implementation as pure virtual method + virtual Item *clone_item_impl () const = 0; + + /* Save having to specify two clone methods in derived classes by making + * statement clone return item clone. Hopefully won't affect performance too + * much. */ + Item *clone_stmt_impl () const final override { return clone_item_impl (); } +}; + +// forward decl of ExprWithoutBlock +class ExprWithoutBlock; + +// Base expression AST node - abstract +class Expr : public Node +{ +public: + // Unique pointer custom clone function + std::unique_ptr clone_expr () const + { + return std::unique_ptr (clone_expr_impl ()); + } + + /* TODO: public methods that could be useful: + * - get_type() - returns type of expression. set_type() may also be useful + * for some? + * - evaluate() - evaluates expression if constant? can_evaluate()? */ + + /* HACK: downcasting without dynamic_cast (if possible) via polymorphism - + * overrided in subclasses of ExprWithoutBlock */ + virtual ExprWithoutBlock *as_expr_without_block () const { return nullptr; } + + virtual std::string as_string () const = 0; + + virtual ~Expr () {} + + virtual Location get_locus () const = 0; + + // HACK: strictly not needed, but faster than full downcast clone + virtual bool is_expr_without_block () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; + + virtual NodeId get_node_id () const { return node_id; } + + virtual void set_node_id (NodeId id) { node_id = id; } + +protected: + // Constructor + Expr () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} + + // Clone function implementation as pure virtual method + virtual Expr *clone_expr_impl () const = 0; + + // TODO: think of less hacky way to implement this kind of thing + // Sets outer attributes. + virtual void set_outer_attrs (std::vector) = 0; + + NodeId node_id; +}; + +// AST node for an expression without an accompanying block - abstract +class ExprWithoutBlock : public Expr +{ +protected: + // pure virtual clone implementation + virtual ExprWithoutBlock *clone_expr_without_block_impl () const = 0; + + /* Save having to specify two clone methods in derived classes by making expr + * clone return exprwithoutblock clone. Hopefully won't affect performance too + * much. */ + ExprWithoutBlock *clone_expr_impl () const final override + { + return clone_expr_without_block_impl (); + } + + bool is_expr_without_block () const final override { return true; }; + +public: + // Unique pointer custom clone function + std::unique_ptr clone_expr_without_block () const + { + return std::unique_ptr (clone_expr_without_block_impl ()); + } + + /* downcasting hack from expr to use pratt parsing with + * parse_expr_without_block */ + ExprWithoutBlock *as_expr_without_block () const final override + { + return clone_expr_without_block_impl (); + } + + virtual ExprWithoutBlock *to_stmt () const { return clone_expr_impl (); } +}; + +/* HACK: IdentifierExpr, delete when figure out identifier vs expr problem in + * Pratt parser */ +/* Alternatively, identifiers could just be represented as single-segment paths + */ +class IdentifierExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + Identifier ident; + Location locus; + +public: + IdentifierExpr (Identifier ident, std::vector outer_attrs, + Location locus) + : outer_attrs (std::move (outer_attrs)), ident (std::move (ident)), + locus (locus) + {} + + std::string as_string () const override { return ident; } + + Location get_locus () const override final { return locus; } + + Identifier get_ident () const { return ident; } + + void accept_vis (ASTVisitor &vis) override; + + // Clones this object. + std::unique_ptr clone_identifier_expr () const + { + return std::unique_ptr (clone_identifier_expr_impl ()); + } + + // "Error state" if ident is empty, so base stripping on this. + void mark_for_strip () override { ident = {}; } + bool is_marked_for_strip () const override { return ident.empty (); } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + // Clone method implementation + IdentifierExpr *clone_expr_without_block_impl () const final override + { + return clone_identifier_expr_impl (); + } + + IdentifierExpr *clone_identifier_expr_impl () const + { + return new IdentifierExpr (*this); + } +}; + +// Pattern base AST node +class Pattern +{ +public: + // Unique pointer custom clone function + std::unique_ptr clone_pattern () const + { + return std::unique_ptr (clone_pattern_impl ()); + } + + // possible virtual methods: is_refutable() + + virtual ~Pattern () {} + + virtual std::string as_string () const = 0; + virtual void accept_vis (ASTVisitor &vis) = 0; + + // as only one kind of pattern can be stripped, have default of nothing + virtual void mark_for_strip () {} + virtual bool is_marked_for_strip () const { return false; } + + virtual Location get_locus () const = 0; + virtual NodeId get_pattern_node_id () const = 0; + +protected: + // Clone pattern implementation as pure virtual method + virtual Pattern *clone_pattern_impl () const = 0; +}; + +// forward decl for Type +class TraitBound; + +// Base class for types as represented in AST - abstract +class Type : public Node +{ +public: + // Unique pointer custom clone function + std::unique_ptr clone_type () const + { + return std::unique_ptr (clone_type_impl ()); + } + + // virtual destructor + virtual ~Type () {} + + virtual std::string as_string () const = 0; + + /* HACK: convert to trait bound. Virtual method overriden by classes that + * enable this. */ + virtual TraitBound *to_trait_bound (bool) const { return nullptr; } + /* as pointer, shouldn't require definition beforehand, only forward + * declaration. */ + + virtual void accept_vis (ASTVisitor &vis) = 0; + + // as only two kinds of types can be stripped, have default of nothing + virtual void mark_for_strip () {} + virtual bool is_marked_for_strip () const { return false; } + + virtual Location get_locus () const = 0; + + NodeId get_node_id () const { return node_id; } + +protected: + Type () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} + + // Clone function implementation as pure virtual method + virtual Type *clone_type_impl () const = 0; + + NodeId node_id; +}; + +// A type without parentheses? - abstract +class TypeNoBounds : public Type +{ +public: + // Unique pointer custom clone function + std::unique_ptr clone_type_no_bounds () const + { + return std::unique_ptr (clone_type_no_bounds_impl ()); + } + +protected: + // Clone function implementation as pure virtual method + virtual TypeNoBounds *clone_type_no_bounds_impl () const = 0; + + /* Save having to specify two clone methods in derived classes by making type + * clone return typenobounds clone. Hopefully won't affect performance too + * much. */ + TypeNoBounds *clone_type_impl () const final override + { + return clone_type_no_bounds_impl (); + } + + TypeNoBounds () : Type () {} +}; + +/* Abstract base class representing a type param bound - Lifetime and TraitBound + * extends it */ +class TypeParamBound +{ +public: + virtual ~TypeParamBound () {} + + // Unique pointer custom clone function + std::unique_ptr clone_type_param_bound () const + { + return std::unique_ptr (clone_type_param_bound_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + NodeId get_node_id () const { return node_id; } + + virtual Location get_locus () const = 0; + +protected: + // Clone function implementation as pure virtual method + virtual TypeParamBound *clone_type_param_bound_impl () const = 0; + + TypeParamBound (NodeId node_id) : node_id (node_id) {} + + NodeId node_id; +}; + +// Represents a lifetime (and is also a kind of type param bound) +class Lifetime : public TypeParamBound +{ +public: + enum LifetimeType + { + NAMED, // corresponds to LIFETIME_OR_LABEL + STATIC, // corresponds to 'static + WILDCARD // corresponds to '_ + }; + +private: + LifetimeType lifetime_type; + std::string lifetime_name; + Location locus; + NodeId node_id; + +public: + // Constructor + Lifetime (LifetimeType type, std::string name = std::string (), + Location locus = Location ()) + : TypeParamBound (Analysis::Mappings::get ()->get_next_node_id ()), + lifetime_type (type), lifetime_name (std::move (name)), locus (locus) + {} + + Lifetime (NodeId id, LifetimeType type, std::string name = std::string (), + Location locus = Location ()) + : TypeParamBound (id), lifetime_type (type), + lifetime_name (std::move (name)), locus (locus) + {} + + // Creates an "error" lifetime. + static Lifetime error () { return Lifetime (NAMED, ""); } + + // Returns true if the lifetime is in an error state. + bool is_error () const + { + return lifetime_type == NAMED && lifetime_name.empty (); + } + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + LifetimeType get_lifetime_type () { return lifetime_type; } + + Location get_locus () const override final { return locus; } + + std::string get_lifetime_name () const { return lifetime_name; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + Lifetime *clone_type_param_bound_impl () const override + { + return new Lifetime (node_id, lifetime_type, lifetime_name, locus); + } +}; + +/* Base generic parameter in AST. Abstract - can be represented by a Lifetime or + * Type param */ +class GenericParam +{ +public: + enum class Kind + { + Lifetime, + Type, + Const, + }; + + virtual ~GenericParam () {} + + // Unique pointer custom clone function + std::unique_ptr clone_generic_param () const + { + return std::unique_ptr (clone_generic_param_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual Location get_locus () const = 0; + + virtual Kind get_kind () const = 0; + + NodeId get_node_id () { return node_id; } + +protected: + GenericParam () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} + GenericParam (NodeId node_id) : node_id (node_id) {} + + // Clone function implementation as pure virtual method + virtual GenericParam *clone_generic_param_impl () const = 0; + + NodeId node_id; +}; + +// A lifetime generic parameter (as opposed to a type generic parameter) +class LifetimeParam : public GenericParam +{ + Lifetime lifetime; + std::vector lifetime_bounds; + Attribute outer_attr; + Location locus; + +public: + Lifetime get_lifetime () const { return lifetime; } + + // Returns whether the lifetime param has any lifetime bounds. + bool has_lifetime_bounds () const { return !lifetime_bounds.empty (); } + + // Returns whether the lifetime param has an outer attribute. + bool has_outer_attribute () const { return !outer_attr.is_empty (); } + + // Creates an error state lifetime param. + static LifetimeParam create_error () + { + return LifetimeParam (Lifetime::error (), {}, Attribute::create_empty (), + Location ()); + } + + // Returns whether the lifetime param is in an error state. + bool is_error () const { return lifetime.is_error (); } + + // Constructor + LifetimeParam (Lifetime lifetime, std::vector lifetime_bounds, + Attribute outer_attr, Location locus) + : lifetime (std::move (lifetime)), + lifetime_bounds (std::move (lifetime_bounds)), + outer_attr (std::move (outer_attr)), locus (locus) + {} + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + Location get_locus () const override final { return locus; } + + Kind get_kind () const override final { return Kind::Lifetime; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + LifetimeParam *clone_generic_param_impl () const override + { + return new LifetimeParam (*this); + } +}; + +// A macro item AST node - abstract base class +class MacroItem : public Item +{ +}; + +// Item used in trait declarations - abstract base class +class TraitItem +{ +protected: + TraitItem () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} + + // Clone function implementation as pure virtual method + virtual TraitItem *clone_trait_item_impl () const = 0; + + NodeId node_id; + +public: + virtual ~TraitItem () {} + + // Unique pointer custom clone function + std::unique_ptr clone_trait_item () const + { + return std::unique_ptr (clone_trait_item_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; + + NodeId get_node_id () const { return node_id; } +}; + +/* Abstract base class for items used within an inherent impl block (the impl + * name {} one) */ +class InherentImplItem +{ +protected: + // Clone function implementation as pure virtual method + virtual InherentImplItem *clone_inherent_impl_item_impl () const = 0; + +public: + virtual ~InherentImplItem () {} + + // Unique pointer custom clone function + std::unique_ptr clone_inherent_impl_item () const + { + return std::unique_ptr (clone_inherent_impl_item_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; + + virtual Location get_locus () const = 0; +}; + +// Abstract base class for items used in a trait impl +class TraitImplItem +{ +protected: + virtual TraitImplItem *clone_trait_impl_item_impl () const = 0; + +public: + virtual ~TraitImplItem (){}; + + // Unique pointer custom clone function + std::unique_ptr clone_trait_impl_item () const + { + return std::unique_ptr (clone_trait_impl_item_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; +}; + +// Abstract base class for an item used inside an extern block +class ExternalItem +{ +public: + ExternalItem () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} + + virtual ~ExternalItem () {} + + // Unique pointer custom clone function + std::unique_ptr clone_external_item () const + { + return std::unique_ptr (clone_external_item_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; + + NodeId get_node_id () const { return node_id; } + +protected: + // Clone function implementation as pure virtual method + virtual ExternalItem *clone_external_item_impl () const = 0; + + NodeId node_id; +}; + +/* Data structure to store the data used in macro invocations and macro + * invocations with semicolons. */ +struct MacroInvocData +{ +private: + SimplePath path; + DelimTokenTree token_tree; + + // One way of parsing the macro. Probably not applicable for all macros. + std::vector > parsed_items; + bool parsed_to_meta_item = false; + +public: + std::string as_string () const; + + MacroInvocData (SimplePath path, DelimTokenTree token_tree) + : path (std::move (path)), token_tree (std::move (token_tree)) + {} + + // Copy constructor with vector clone + MacroInvocData (const MacroInvocData &other) + : path (other.path), token_tree (other.token_tree), + parsed_to_meta_item (other.parsed_to_meta_item) + { + parsed_items.reserve (other.parsed_items.size ()); + for (const auto &e : other.parsed_items) + parsed_items.push_back (e->clone_meta_item_inner ()); + } + + // Copy assignment operator with vector clone + MacroInvocData &operator= (const MacroInvocData &other) + { + path = other.path; + token_tree = other.token_tree; + parsed_to_meta_item = other.parsed_to_meta_item; + + parsed_items.reserve (other.parsed_items.size ()); + for (const auto &e : other.parsed_items) + parsed_items.push_back (e->clone_meta_item_inner ()); + + return *this; + } + + // Move constructors + MacroInvocData (MacroInvocData &&other) = default; + MacroInvocData &operator= (MacroInvocData &&other) = default; + + // Invalid if path is empty, so base stripping on that. + void mark_for_strip () { path = SimplePath::create_empty (); } + bool is_marked_for_strip () const { return path.is_empty (); } + + // Returns whether the macro has been parsed already. + bool is_parsed () const { return parsed_to_meta_item; } + // TODO: update on other ways of parsing it + + // TODO: this mutable getter seems kinda dodgy + DelimTokenTree &get_delim_tok_tree () { return token_tree; } + const DelimTokenTree &get_delim_tok_tree () const { return token_tree; } + + // TODO: this mutable getter seems kinda dodgy + SimplePath &get_path () { return path; } + const SimplePath &get_path () const { return path; } + + void + set_meta_item_output (std::vector > new_items) + { + parsed_items = std::move (new_items); + } + // TODO: mutable getter seems kinda dodgy + std::vector > &get_meta_items () + { + return parsed_items; + } + const std::vector > &get_meta_items () const + { + return parsed_items; + } +}; + +class SingleASTNode +{ +public: + enum NodeType + { + EXPRESSION, + ITEM, + STMT, + EXTERN, + TRAIT, + IMPL, + TRAIT_IMPL, + TYPE, + }; + +private: + NodeType kind; + + // FIXME make this a union + std::unique_ptr expr; + std::unique_ptr item; + std::unique_ptr stmt; + std::unique_ptr external_item; + std::unique_ptr trait_item; + std::unique_ptr impl_item; + std::unique_ptr trait_impl_item; + std::unique_ptr type; + +public: + SingleASTNode (std::unique_ptr expr) + : kind (EXPRESSION), expr (std::move (expr)) + {} + + SingleASTNode (std::unique_ptr item) + : kind (ITEM), item (std::move (item)) + {} + + SingleASTNode (std::unique_ptr stmt) + : kind (STMT), stmt (std::move (stmt)) + {} + + SingleASTNode (std::unique_ptr item) + : kind (EXTERN), external_item (std::move (item)) + {} + + SingleASTNode (std::unique_ptr item) + : kind (TRAIT), trait_item (std::move (item)) + {} + + SingleASTNode (std::unique_ptr item) + : kind (IMPL), impl_item (std::move (item)) + {} + + SingleASTNode (std::unique_ptr trait_impl_item) + : kind (TRAIT_IMPL), trait_impl_item (std::move (trait_impl_item)) + {} + + SingleASTNode (std::unique_ptr type) + : kind (TYPE), type (std::move (type)) + {} + + SingleASTNode (SingleASTNode const &other) + { + kind = other.kind; + switch (kind) + { + case EXPRESSION: + expr = other.expr->clone_expr (); + break; + + case ITEM: + item = other.item->clone_item (); + break; + + case STMT: + stmt = other.stmt->clone_stmt (); + break; + + case EXTERN: + external_item = other.external_item->clone_external_item (); + break; + + case TRAIT: + trait_item = other.trait_item->clone_trait_item (); + break; + + case IMPL: + impl_item = other.impl_item->clone_inherent_impl_item (); + break; + + case TRAIT_IMPL: + trait_impl_item = other.trait_impl_item->clone_trait_impl_item (); + break; + + case TYPE: + type = other.type->clone_type (); + break; + } + } + + SingleASTNode operator= (SingleASTNode const &other) + { + kind = other.kind; + switch (kind) + { + case EXPRESSION: + expr = other.expr->clone_expr (); + break; + + case ITEM: + item = other.item->clone_item (); + break; + + case STMT: + stmt = other.stmt->clone_stmt (); + break; + + case EXTERN: + external_item = other.external_item->clone_external_item (); + break; + + case TRAIT: + trait_item = other.trait_item->clone_trait_item (); + break; + + case IMPL: + impl_item = other.impl_item->clone_inherent_impl_item (); + break; + + case TRAIT_IMPL: + trait_impl_item = other.trait_impl_item->clone_trait_impl_item (); + break; + + case TYPE: + type = other.type->clone_type (); + break; + } + return *this; + } + + SingleASTNode (SingleASTNode &&other) = default; + SingleASTNode &operator= (SingleASTNode &&other) = default; + + NodeType get_kind () const { return kind; } + + std::unique_ptr &get_expr () + { + rust_assert (kind == EXPRESSION); + return expr; + } + + std::unique_ptr &get_item () + { + rust_assert (kind == ITEM); + return item; + } + + std::unique_ptr &get_stmt () + { + rust_assert (kind == STMT); + return stmt; + } + + /** + * Access the inner nodes and take ownership of them. + * You can only call these functions once per node + */ + + std::unique_ptr take_stmt () + { + rust_assert (!is_error ()); + return std::move (stmt); + } + + std::unique_ptr take_expr () + { + rust_assert (!is_error ()); + return std::move (expr); + } + + std::unique_ptr take_item () + { + rust_assert (!is_error ()); + return std::move (item); + } + + std::unique_ptr take_trait_item () + { + rust_assert (!is_error ()); + return std::move (trait_item); + } + + std::unique_ptr take_external_item () + { + rust_assert (!is_error ()); + return std::move (external_item); + } + + std::unique_ptr take_impl_item () + { + rust_assert (!is_error ()); + return std::move (impl_item); + } + + std::unique_ptr take_trait_impl_item () + { + rust_assert (!is_error ()); + return std::move (trait_impl_item); + } + + std::unique_ptr take_type () + { + rust_assert (!is_error ()); + return std::move (type); + } + + void accept_vis (ASTVisitor &vis) + { + switch (kind) + { + case EXPRESSION: + expr->accept_vis (vis); + break; + + case ITEM: + item->accept_vis (vis); + break; + + case STMT: + stmt->accept_vis (vis); + break; + + case EXTERN: + external_item->accept_vis (vis); + break; + + case TRAIT: + trait_item->accept_vis (vis); + break; + + case IMPL: + impl_item->accept_vis (vis); + break; + + case TRAIT_IMPL: + trait_impl_item->accept_vis (vis); + break; + + case TYPE: + type->accept_vis (vis); + break; + } + } + + bool is_error () + { + switch (kind) + { + case EXPRESSION: + return expr == nullptr; + case ITEM: + return item == nullptr; + case STMT: + return stmt == nullptr; + case EXTERN: + return external_item == nullptr; + case TRAIT: + return trait_item == nullptr; + case IMPL: + return impl_item == nullptr; + case TRAIT_IMPL: + return trait_impl_item == nullptr; + case TYPE: + return type == nullptr; + } + + gcc_unreachable (); + return true; + } + + std::string as_string () + { + switch (kind) + { + case EXPRESSION: + return "Expr: " + expr->as_string (); + case ITEM: + return "Item: " + item->as_string (); + case STMT: + return "Stmt: " + stmt->as_string (); + case EXTERN: + return "External Item: " + external_item->as_string (); + case TRAIT: + return "Trait Item: " + trait_item->as_string (); + case IMPL: + return "Impl Item: " + impl_item->as_string (); + case TRAIT_IMPL: + return "Trait Impl Item: " + trait_impl_item->as_string (); + case TYPE: + return "Type: " + type->as_string (); + } + + gcc_unreachable (); + return ""; + } +}; + +/* Basically, a "fragment" that can be incorporated into the AST, created as + * a result of macro expansion. Really annoying to work with due to the fact + * that macros can really expand to anything. As such, horrible representation + * at the moment. */ +class ASTFragment +{ +private: + /* basic idea: essentially, a vector of tagged unions of different AST node + * types. Now, this could actually be stored without a tagged union if the + * different AST node types had a unified parent, but that would create + * issues with the diamond problem or significant performance penalties. So + * a tagged union had to be used instead. A vector is used to represent the + * ability for a macro to expand to two statements, for instance. */ + + std::vector nodes; + bool fragment_is_error; + + /** + * We need to make a special case for Expression and Type fragments as only + * one Node will be extracted from the `nodes` vector + */ + + bool is_single_fragment () const { return nodes.size () == 1; } + + bool is_single_fragment_kind (SingleASTNode::NodeType kind) const + { + return is_single_fragment () && nodes[0].get_kind () == kind; + } + +public: + ASTFragment (std::vector nodes, bool fragment_is_error = false) + : nodes (std::move (nodes)), fragment_is_error (fragment_is_error) + { + if (fragment_is_error) + rust_assert (nodes.empty ()); + } + + ASTFragment (ASTFragment const &other) + : fragment_is_error (other.fragment_is_error) + { + nodes.clear (); + nodes.reserve (other.nodes.size ()); + for (auto &n : other.nodes) + { + nodes.push_back (n); + } + } + + ASTFragment &operator= (ASTFragment const &other) + { + fragment_is_error = other.fragment_is_error; + nodes.clear (); + nodes.reserve (other.nodes.size ()); + for (auto &n : other.nodes) + { + nodes.push_back (n); + } + + return *this; + } + + static ASTFragment create_error () { return ASTFragment ({}, true); } + + std::vector &get_nodes () { return nodes; } + bool is_error () const { return fragment_is_error; } + + bool should_expand () const { return !is_error (); } + + std::unique_ptr take_expression_fragment () + { + rust_assert (is_single_fragment_kind (SingleASTNode::NodeType::EXPRESSION)); + return nodes[0].take_expr (); + } + + std::unique_ptr take_type_fragment () + { + rust_assert (is_single_fragment_kind (SingleASTNode::NodeType::TYPE)); + return nodes[0].take_type (); + } + + void accept_vis (ASTVisitor &vis) + { + for (auto &node : nodes) + node.accept_vis (vis); + } +}; + +// A crate AST object - holds all the data for a single compilation unit +struct Crate +{ + std::vector inner_attrs; + // dodgy spacing required here + /* TODO: is it better to have a vector of items here or a module (implicit + * top-level one)? */ + std::vector > items; + + NodeId node_id; + +public: + // Constructor + Crate (std::vector > items, + std::vector inner_attrs) + : inner_attrs (std::move (inner_attrs)), items (std::move (items)), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + // Copy constructor with vector clone + Crate (Crate const &other) + : inner_attrs (other.inner_attrs), node_id (other.node_id) + { + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_item ()); + } + + ~Crate () = default; + + // Overloaded assignment operator with vector clone + Crate &operator= (Crate const &other) + { + inner_attrs = other.inner_attrs; + node_id = other.node_id; + + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_item ()); + + return *this; + } + + // Move constructors + Crate (Crate &&other) = default; + Crate &operator= (Crate &&other) = default; + + // Get crate representation as string (e.g. for debugging). + std::string as_string () const; + + // Delete all crate information, e.g. if fails cfg. + void strip_crate () + { + inner_attrs.clear (); + inner_attrs.shrink_to_fit (); + + items.clear (); + items.shrink_to_fit (); + // TODO: is this the best way to do this? + } + + NodeId get_node_id () const { return node_id; } + const std::vector &get_inner_attrs () const { return inner_attrs; } +}; + +// Base path expression AST node - abstract +class PathExpr : public ExprWithoutBlock +{ +}; +} // namespace AST +} // namespace Rust + +#endif diff --git a/gcc/rust/operator.h b/gcc/rust/operator.h new file mode 100644 index 00000000000..6813db3ed13 --- /dev/null +++ b/gcc/rust/operator.h @@ -0,0 +1,72 @@ +// Copyright (C) 2020-2022 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 +// . + +#ifndef RUST_OPERATOR_H +#define RUST_OPERATOR_H + +enum class NegationOperator +{ + NEGATE, + NOT +}; + +enum class ArithmeticOrLogicalOperator +{ + ADD, // std::ops::Add + SUBTRACT, // std::ops::Sub + MULTIPLY, // std::ops::Mul + DIVIDE, // std::ops::Div + MODULUS, // std::ops::Rem + BITWISE_AND, // std::ops::BitAnd + BITWISE_OR, // std::ops::BitOr + BITWISE_XOR, // std::ops::BitXor + LEFT_SHIFT, // std::ops::Shl + RIGHT_SHIFT // std::ops::Shr +}; + +enum class ComparisonOperator +{ + EQUAL, // std::cmp::PartialEq::eq + NOT_EQUAL, // std::cmp::PartialEq::ne + GREATER_THAN, // std::cmp::PartialEq::gt + LESS_THAN, // std::cmp::PartialEq::lt + GREATER_OR_EQUAL, // std::cmp::PartialEq::ge + LESS_OR_EQUAL // std::cmp::PartialEq::le +}; + +enum class LazyBooleanOperator +{ + LOGICAL_OR, + LOGICAL_AND +}; + +enum class CompoundAssignmentOperator +{ + ADD, // std::ops::AddAssign + SUBTRACT, // std::ops::SubAssign + MULTIPLY, // std::ops::MulAssign + DIVIDE, // std::ops::DivAssign + MODULUS, // std::ops::RemAssign + BITWISE_AND, // std::ops::BitAndAssign + BITWISE_OR, // std::ops::BitOrAssign + BITWISE_XOR, // std::ops::BitXorAssign + LEFT_SHIFT, // std::ops::ShlAssign + RIGHT_SHIFT // std::ops::ShrAssign +}; + +#endif // RUST_OPERATOR_H From patchwork Tue Dec 6 10:13:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61511 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D0A7E382CD60 for ; Tue, 6 Dec 2022 10:18:30 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by sourceware.org (Postfix) with ESMTPS id 754CF396D82C for ; Tue, 6 Dec 2022 10:12:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 754CF396D82C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x433.google.com with SMTP id q7so22748634wrr.8 for ; Tue, 06 Dec 2022 02:12:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=s31+94ibpaypK+HnIO+osDZnfVQoRGVFeQv57fpzhN4=; b=YSWY+V+cimWuQt0t5fc/V7FgetrCtcbg0uXnHYjkhe1AFifUDIkd+VACKbqiEeg9jS PWjn3heRWcPAuKVnsM84ns1R/ur/598GST7irCC6x5JKkymBO5GvRoavgtj2sghO49yp B53/2+HxbKXtUmGgd6idyVroctnvz1CvvB4iEe9yv1CubO2UK5QZF2yjUCokQSWRw3j6 QVW5kPPLglPPKK+koG1wHzAXjKGNwUwg1LwWUDshe+AjviToKa/nNxLg/24nj2VaIJuL 5ZR1p1z/w2pLxlBD1co4SMGwm18qFTMjiOXTHOw45oMcNxd8vurzbVl+ZZEvaFzHcX7j vqow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=s31+94ibpaypK+HnIO+osDZnfVQoRGVFeQv57fpzhN4=; b=DV6BSUbI05p6PLjCDYQdg1+u/L8Py68XPTrEunKAYPylTVsfnlQJFry4ZhUzCqotWi 5zMi7l2UUBXcvOu3ArcrmetyG//vKQMlfg5oag0vix7ApGx6q5ec+mdxPuJ+O5VsOd45 PFx8LZ0XVorYwUAwM1aM/bazENz1A1LnqqlX1oE/cL2zMdEAYTRBf9XCtSXJUrmxFE0W GOB3Wffhy3JPHkl6oiyEtT1db29SZpNVue896pl1ItKmDFny4iUtHmv89HdGGIdn1axi t1Xg64A69NLztGbUwPk/k5aw+P6FrhB2oCbWMq9Q7y9zEFLwB3OoGBTpsxxlt9KaQori kLvw== X-Gm-Message-State: ANoB5plOMeoDQdLn6/8V70mc5zL9gWMCll0ksEgTNCfi44LsvM51wque 7gFGn7S9Pw7f3GNerHvtCHWj6d7LBe5stJQpaA== X-Google-Smtp-Source: AA0mqf6GlMRWMsRbfEL7npXff7B4fbBA7zcyQgerJGXf0SJMe8ogqjTPTJldAFQPapT+9sSxKR0tIg== X-Received: by 2002:a5d:6244:0:b0:236:73b2:f026 with SMTP id m4-20020a5d6244000000b0023673b2f026mr53294308wrv.396.1670321519310; Tue, 06 Dec 2022 02:11:59 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.11.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:11:58 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, The Other , Philip Herron Subject: [PATCH Rust front-end v4 09/46] gccrs: Add definitions of Rust Items in AST data structures Date: Tue, 6 Dec 2022 11:13:41 +0100 Message-Id: <20221206101417.778807-10-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-27.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: The Other This adds the proper definitions of our AST Item nodes. Co-authored-by: Philip Herron --- gcc/rust/ast/rust-item.h | 4382 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 4382 insertions(+) create mode 100644 gcc/rust/ast/rust-item.h diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h new file mode 100644 index 00000000000..4987674cba1 --- /dev/null +++ b/gcc/rust/ast/rust-item.h @@ -0,0 +1,4382 @@ +// Copyright (C) 2020-2022 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 +// . + +#ifndef RUST_AST_ITEM_H +#define RUST_AST_ITEM_H + +#include "rust-ast.h" +#include "rust-path.h" +#include "rust-common.h" + +namespace Rust { +namespace AST { +// forward decls +class BlockExpr; +class TypePath; + +// TODO: inline? +/*struct AbiName { + std::string abi_name; + // Technically is meant to be STRING_LITERAL + + public: + // Returns whether abi name is empty, i.e. doesn't exist. + bool is_empty() const { + return abi_name.empty(); + } + + AbiName(std::string name) : abi_name(std::move(name)) {} + + // Empty AbiName constructor + AbiName() {} +};*/ + +// A type generic parameter (as opposed to a lifetime generic parameter) +class TypeParam : public GenericParam +{ + // bool has_outer_attribute; + // std::unique_ptr outer_attr; + Attribute outer_attr; + + Identifier type_representation; + + // bool has_type_param_bounds; + // TypeParamBounds type_param_bounds; + std::vector> + type_param_bounds; // inlined form + + // bool has_type; + std::unique_ptr type; + + Location locus; + +public: + Identifier get_type_representation () const { return type_representation; } + + // Returns whether the type of the type param has been specified. + bool has_type () const { return type != nullptr; } + + // Returns whether the type param has type param bounds. + bool has_type_param_bounds () const { return !type_param_bounds.empty (); } + + // Returns whether the type param has an outer attribute. + bool has_outer_attribute () const { return !outer_attr.is_empty (); } + + TypeParam (Identifier type_representation, Location locus = Location (), + std::vector> type_param_bounds + = std::vector> (), + std::unique_ptr type = nullptr, + Attribute outer_attr = Attribute::create_empty ()) + : GenericParam (Analysis::Mappings::get ()->get_next_node_id ()), + outer_attr (std::move (outer_attr)), + type_representation (std::move (type_representation)), + type_param_bounds (std::move (type_param_bounds)), + type (std::move (type)), locus (locus) + {} + + // Copy constructor uses clone + TypeParam (TypeParam const &other) + : GenericParam (other.node_id), outer_attr (other.outer_attr), + type_representation (other.type_representation), locus (other.locus) + { + // guard to prevent null pointer dereference + if (other.type != nullptr) + type = other.type->clone_type (); + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + } + + // Overloaded assignment operator to clone + TypeParam &operator= (TypeParam const &other) + { + type_representation = other.type_representation; + outer_attr = other.outer_attr; + locus = other.locus; + node_id = other.node_id; + + // guard to prevent null pointer dereference + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + return *this; + } + + // move constructors + TypeParam (TypeParam &&other) = default; + TypeParam &operator= (TypeParam &&other) = default; + + std::string as_string () const override; + + Location get_locus () const override final { return locus; } + + Kind get_kind () const override final { return Kind::Type; } + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type () + { + rust_assert (type != nullptr); + return type; + } + + // TODO: mutable getter seems kinda dodgy + std::vector> &get_type_param_bounds () + { + return type_param_bounds; + } + const std::vector> & + get_type_param_bounds () const + { + return type_param_bounds; + } + +protected: + // Clone function implementation as virtual method + TypeParam *clone_generic_param_impl () const override + { + return new TypeParam (*this); + } +}; + +/* "where" clause item base. Abstract - use LifetimeWhereClauseItem, + * TypeBoundWhereClauseItem */ +class WhereClauseItem +{ +public: + virtual ~WhereClauseItem () {} + + // Unique pointer custom clone function + std::unique_ptr clone_where_clause_item () const + { + return std::unique_ptr (clone_where_clause_item_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual NodeId get_node_id () const = 0; + +protected: + // Clone function implementation as pure virtual method + virtual WhereClauseItem *clone_where_clause_item_impl () const = 0; +}; + +// A lifetime where clause item +class LifetimeWhereClauseItem : public WhereClauseItem +{ + Lifetime lifetime; + std::vector lifetime_bounds; + Location locus; + NodeId node_id; + +public: + LifetimeWhereClauseItem (Lifetime lifetime, + std::vector lifetime_bounds, + Location locus) + : lifetime (std::move (lifetime)), + lifetime_bounds (std::move (lifetime_bounds)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + NodeId get_node_id () const override final { return node_id; } + + Lifetime &get_lifetime () { return lifetime; } + + std::vector &get_lifetime_bounds () { return lifetime_bounds; } + + Location get_locus () const { return locus; } + +protected: + // Clone function implementation as (not pure) virtual method + LifetimeWhereClauseItem *clone_where_clause_item_impl () const override + { + return new LifetimeWhereClauseItem (*this); + } +}; + +// A type bound where clause item +class TypeBoundWhereClauseItem : public WhereClauseItem +{ + std::vector for_lifetimes; + std::unique_ptr bound_type; + std::vector> type_param_bounds; + NodeId node_id; + Location locus; + +public: + // Returns whether the item has ForLifetimes + bool has_for_lifetimes () const { return !for_lifetimes.empty (); } + + // Returns whether the item has type param bounds + bool has_type_param_bounds () const { return !type_param_bounds.empty (); } + + TypeBoundWhereClauseItem ( + std::vector for_lifetimes, std::unique_ptr bound_type, + std::vector> type_param_bounds, + Location locus) + : for_lifetimes (std::move (for_lifetimes)), + bound_type (std::move (bound_type)), + type_param_bounds (std::move (type_param_bounds)), + node_id (Analysis::Mappings::get ()->get_next_node_id ()), locus (locus) + {} + + // Copy constructor requires clone + TypeBoundWhereClauseItem (TypeBoundWhereClauseItem const &other) + : for_lifetimes (other.for_lifetimes), + bound_type (other.bound_type->clone_type ()) + { + node_id = other.node_id; + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + } + + // Overload assignment operator to clone + TypeBoundWhereClauseItem &operator= (TypeBoundWhereClauseItem const &other) + { + node_id = other.node_id; + for_lifetimes = other.for_lifetimes; + bound_type = other.bound_type->clone_type (); + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + return *this; + } + + // move constructors + TypeBoundWhereClauseItem (TypeBoundWhereClauseItem &&other) = default; + TypeBoundWhereClauseItem &operator= (TypeBoundWhereClauseItem &&other) + = default; + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + std::unique_ptr &get_type () + { + rust_assert (bound_type != nullptr); + return bound_type; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector> &get_type_param_bounds () + { + return type_param_bounds; + } + + const std::vector> & + get_type_param_bounds () const + { + return type_param_bounds; + } + + NodeId get_node_id () const override final { return node_id; } + + Location get_locus () const { return locus; } + +protected: + // Clone function implementation as (not pure) virtual method + TypeBoundWhereClauseItem *clone_where_clause_item_impl () const override + { + return new TypeBoundWhereClauseItem (*this); + } +}; + +// A where clause +struct WhereClause +{ +private: + std::vector> where_clause_items; + NodeId node_id; + +public: + WhereClause (std::vector> where_clause_items) + : where_clause_items (std::move (where_clause_items)), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + // copy constructor with vector clone + WhereClause (WhereClause const &other) + { + node_id = other.node_id; + where_clause_items.reserve (other.where_clause_items.size ()); + for (const auto &e : other.where_clause_items) + where_clause_items.push_back (e->clone_where_clause_item ()); + } + + // overloaded assignment operator with vector clone + WhereClause &operator= (WhereClause const &other) + { + node_id = other.node_id; + where_clause_items.reserve (other.where_clause_items.size ()); + for (const auto &e : other.where_clause_items) + where_clause_items.push_back (e->clone_where_clause_item ()); + + return *this; + } + + // move constructors + WhereClause (WhereClause &&other) = default; + WhereClause &operator= (WhereClause &&other) = default; + + // Creates a WhereClause with no items. + static WhereClause create_empty () + { + return WhereClause (std::vector> ()); + } + + // Returns whether the WhereClause has no items. + bool is_empty () const { return where_clause_items.empty (); } + + std::string as_string () const; + + NodeId get_node_id () const { return node_id; } + + // TODO: this mutable getter seems kinda dodgy + std::vector> &get_items () + { + return where_clause_items; + } + const std::vector> &get_items () const + { + return where_clause_items; + } +}; + +// A self parameter in a method +struct SelfParam +{ +private: + bool has_ref; + bool is_mut; + // bool has_lifetime; // only possible if also ref + Lifetime lifetime; + + // bool has_type; // only possible if not ref + std::unique_ptr type; + + NodeId node_id; + + Location locus; + + // Unrestricted constructor used for error state + SelfParam (Lifetime lifetime, bool has_ref, bool is_mut, Type *type) + : has_ref (has_ref), is_mut (is_mut), lifetime (std::move (lifetime)), + type (type), node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + // this is ok as no outside classes can ever call this + + // TODO: self param can have outer attributes + +public: + // Returns whether the self-param has a type field. + bool has_type () const { return type != nullptr; } + + // Returns whether the self-param has a valid lifetime. + bool has_lifetime () const { return !lifetime.is_error (); } + + // Returns whether the self-param is in an error state. + bool is_error () const + { + return (has_type () && has_lifetime ()) || (has_lifetime () && !has_ref); + // not having either is not an error + } + + // Creates an error state self-param. + static SelfParam create_error () + { + // cannot have no ref but have a lifetime at the same time + return SelfParam (Lifetime (Lifetime::STATIC), false, false, nullptr); + } + + // Type-based self parameter (not ref, no lifetime) + SelfParam (std::unique_ptr type, bool is_mut, Location locus) + : has_ref (false), is_mut (is_mut), lifetime (Lifetime::error ()), + type (std::move (type)), + node_id (Analysis::Mappings::get ()->get_next_node_id ()), locus (locus) + {} + + // Lifetime-based self parameter (is ref, no type) + SelfParam (Lifetime lifetime, bool is_mut, Location locus) + : has_ref (true), is_mut (is_mut), lifetime (std::move (lifetime)), + node_id (Analysis::Mappings::get ()->get_next_node_id ()), locus (locus) + {} + + // Copy constructor requires clone + SelfParam (SelfParam const &other) + : has_ref (other.has_ref), is_mut (other.is_mut), lifetime (other.lifetime), + node_id (Analysis::Mappings::get ()->get_next_node_id ()), + locus (other.locus) + { + node_id = other.node_id; + if (other.type != nullptr) + type = other.type->clone_type (); + } + + // Overload assignment operator to use clone + SelfParam &operator= (SelfParam const &other) + { + is_mut = other.is_mut; + has_ref = other.has_ref; + lifetime = other.lifetime; + locus = other.locus; + node_id = other.node_id; + + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + + return *this; + } + + // move constructors + SelfParam (SelfParam &&other) = default; + SelfParam &operator= (SelfParam &&other) = default; + + std::string as_string () const; + + Location get_locus () const { return locus; } + + bool get_has_ref () const { return has_ref; }; + bool get_is_mut () const { return is_mut; } + + Lifetime get_lifetime () const { return lifetime; } + + NodeId get_node_id () const { return node_id; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type () + { + rust_assert (has_type ()); + return type; + } +}; + +// Qualifiers for function, i.e. const, unsafe, extern etc. +struct FunctionQualifiers +{ +private: + AsyncConstStatus const_status; + bool has_unsafe; + bool has_extern; + std::string extern_abi; + Location locus; + +public: + FunctionQualifiers (Location locus, AsyncConstStatus const_status, + bool has_unsafe, bool has_extern = false, + std::string extern_abi = std::string ()) + : const_status (const_status), has_unsafe (has_unsafe), + has_extern (has_extern), extern_abi (std::move (extern_abi)), + locus (locus) + { + if (!this->extern_abi.empty ()) + { + // having extern is required; not having it is an implementation error + rust_assert (has_extern); + } + } + + std::string as_string () const; + + AsyncConstStatus get_const_status () const { return const_status; } + bool is_unsafe () const { return has_unsafe; } + bool is_extern () const { return has_extern; } + std::string get_extern_abi () const { return extern_abi; } + bool has_abi () const { return !extern_abi.empty (); } + + Location get_locus () const { return locus; } +}; + +// A function parameter +struct FunctionParam +{ +private: + std::vector outer_attrs; + Location locus; + std::unique_ptr param_name; + std::unique_ptr type; + +public: + FunctionParam (std::unique_ptr param_name, + std::unique_ptr param_type, + std::vector outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), locus (locus), + param_name (std::move (param_name)), type (std::move (param_type)), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + // Copy constructor uses clone + FunctionParam (FunctionParam const &other) + : locus (other.locus), node_id (other.node_id) + { + // guard to prevent nullptr dereference + if (other.param_name != nullptr) + param_name = other.param_name->clone_pattern (); + if (other.type != nullptr) + type = other.type->clone_type (); + } + + // Overload assignment operator to use clone + FunctionParam &operator= (FunctionParam const &other) + { + locus = other.locus; + node_id = other.node_id; + + // guard to prevent nullptr dereference + if (other.param_name != nullptr) + param_name = other.param_name->clone_pattern (); + else + param_name = nullptr; + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + + return *this; + } + + // move constructors + FunctionParam (FunctionParam &&other) = default; + FunctionParam &operator= (FunctionParam &&other) = default; + + // Returns whether FunctionParam is in an invalid state. + bool is_error () const { return param_name == nullptr || type == nullptr; } + + // Creates an error FunctionParam. + static FunctionParam create_error () + { + return FunctionParam (nullptr, nullptr, {}, Location ()); + } + + std::string as_string () const; + + Location get_locus () const { return locus; } + + // TODO: seems kinda dodgy. Think of better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_pattern () + { + rust_assert (param_name != nullptr); + return param_name; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type () + { + rust_assert (type != nullptr); + return type; + } + NodeId get_node_id () const { return node_id; } + +protected: + NodeId node_id; +}; + +// Visibility of item - if the item has it, then it is some form of public +struct Visibility +{ +public: + enum VisType + { + PRIV, + PUB, + PUB_CRATE, + PUB_SELF, + PUB_SUPER, + PUB_IN_PATH + }; + +private: + VisType vis_type; + // Only assigned if vis_type is IN_PATH + SimplePath in_path; + + // should this store location info? + +public: + // Creates a Visibility - TODO make constructor protected or private? + Visibility (VisType vis_type, SimplePath in_path) + : vis_type (vis_type), in_path (std::move (in_path)) + {} + + VisType get_public_vis_type () const { return vis_type; } + + // Returns whether visibility is in an error state. + bool is_error () const + { + return vis_type == PUB_IN_PATH && in_path.is_empty (); + } + + // Returns whether a visibility has a path + bool has_path () const { return !(is_error ()) && vis_type == PUB_IN_PATH; } + + // Returns whether visibility is public or not. + bool is_public () const { return vis_type != PRIV && !is_error (); } + + // Creates an error visibility. + static Visibility create_error () + { + return Visibility (PUB_IN_PATH, SimplePath::create_empty ()); + } + + // Unique pointer custom clone function + /*std::unique_ptr clone_visibility() const { + return std::unique_ptr(clone_visibility_impl()); + }*/ + + /* TODO: think of a way to only allow valid Visibility states - polymorphism + * is one idea but may be too resource-intensive. */ + + // Creates a public visibility with no further features/arguments. + static Visibility create_public () + { + return Visibility (PUB, SimplePath::create_empty ()); + } + + // Creates a public visibility with crate-relative paths + static Visibility create_crate (Location crate_tok_location) + { + return Visibility (PUB_CRATE, + SimplePath::from_str ("crate", crate_tok_location)); + } + + // Creates a public visibility with self-relative paths + static Visibility create_self (Location self_tok_location) + { + return Visibility (PUB_SELF, + SimplePath::from_str ("self", self_tok_location)); + } + + // Creates a public visibility with parent module-relative paths + static Visibility create_super (Location super_tok_location) + { + return Visibility (PUB_SUPER, + SimplePath::from_str ("super", super_tok_location)); + } + + // Creates a private visibility + static Visibility create_private () + { + return Visibility (PRIV, SimplePath::create_empty ()); + } + + // Creates a public visibility with a given path or whatever. + static Visibility create_in_path (SimplePath in_path) + { + return Visibility (PUB_IN_PATH, std::move (in_path)); + } + + std::string as_string () const; + const SimplePath &get_path () const { return in_path; } + SimplePath &get_path () { return in_path; } + +protected: + // Clone function implementation - not currently virtual but may be if + // polymorphism used + /*virtual*/ Visibility *clone_visibility_impl () const + { + return new Visibility (*this); + } +}; + +// A method (function belonging to a type) +class Method : public InherentImplItem, public TraitImplItem +{ + std::vector outer_attrs; + Visibility vis; + FunctionQualifiers qualifiers; + Identifier method_name; + std::vector> generic_params; + SelfParam self_param; + std::vector function_params; + std::unique_ptr return_type; + WhereClause where_clause; + std::unique_ptr function_body; + Location locus; + NodeId node_id; + +public: + // Returns whether the method is in an error state. + bool is_error () const + { + return function_body == nullptr || method_name.empty () + || self_param.is_error (); + } + + // Creates an error state method. + static Method create_error () + { + return Method ("", FunctionQualifiers (Location (), NONE, true), + std::vector> (), + SelfParam::create_error (), std::vector (), + nullptr, WhereClause::create_empty (), nullptr, + Visibility::create_error (), std::vector (), {}); + } + + // Returns whether the method has generic parameters. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether the method has parameters. + bool has_params () const { return !function_params.empty (); } + + // Returns whether the method has a return type (void otherwise). + bool has_return_type () const { return return_type != nullptr; } + + // Returns whether the where clause exists (i.e. has items) + bool has_where_clause () const { return !where_clause.is_empty (); } + + // Returns whether method has a non-default visibility. + bool has_visibility () const { return !vis.is_error (); } + + // Mega-constructor with all possible fields + Method (Identifier method_name, FunctionQualifiers qualifiers, + std::vector> generic_params, + SelfParam self_param, std::vector function_params, + std::unique_ptr return_type, WhereClause where_clause, + std::unique_ptr function_body, Visibility vis, + std::vector outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), vis (std::move (vis)), + qualifiers (std::move (qualifiers)), + method_name (std::move (method_name)), + generic_params (std::move (generic_params)), + self_param (std::move (self_param)), + function_params (std::move (function_params)), + return_type (std::move (return_type)), + where_clause (std::move (where_clause)), + function_body (std::move (function_body)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + // TODO: add constructor with less fields + + // Copy constructor with clone + Method (Method const &other) + : outer_attrs (other.outer_attrs), vis (other.vis), + qualifiers (other.qualifiers), method_name (other.method_name), + self_param (other.self_param), function_params (other.function_params), + where_clause (other.where_clause), locus (other.locus) + { + // guard to prevent null dereference (always required) + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + + // guard to prevent null dereference (only required if error state) + if (other.function_body != nullptr) + function_body = other.function_body->clone_block_expr (); + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + node_id = other.node_id; + } + + // Overloaded assignment operator to clone + Method &operator= (Method const &other) + { + method_name = other.method_name; + outer_attrs = other.outer_attrs; + vis = other.vis; + qualifiers = other.qualifiers; + self_param = other.self_param; + function_params = other.function_params; + where_clause = other.where_clause; + locus = other.locus; + + // guard to prevent null dereference (always required) + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + + // guard to prevent null dereference (only required if error state) + if (other.function_body != nullptr) + function_body = other.function_body->clone_block_expr (); + else + function_body = nullptr; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + node_id = other.node_id; + + return *this; + } + + // move constructors + Method (Method &&other) = default; + Method &operator= (Method &&other) = default; + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if block is null, so base stripping on that. + void mark_for_strip () override { function_body = nullptr; } + bool is_marked_for_strip () const override + { + return function_body == nullptr; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + std::vector &get_function_params () { return function_params; } + const std::vector &get_function_params () const + { + return function_params; + } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_definition () + { + rust_assert (function_body != nullptr); + return function_body; + } + + SelfParam &get_self_param () { return self_param; } + const SelfParam &get_self_param () const { return self_param; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () { return where_clause; } + + Identifier get_method_name () const { return method_name; } + + NodeId get_node_id () const { return node_id; } + + Location get_locus () const override final { return locus; } + + FunctionQualifiers get_qualifiers () { return qualifiers; } + + const Visibility &get_visibility () const { return vis; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + Method *clone_inherent_impl_item_impl () const final override + { + return clone_method_impl (); + } + + /* Use covariance to implement clone function as returning this object + * rather than base */ + Method *clone_trait_impl_item_impl () const final override + { + return clone_method_impl (); + } + + /*virtual*/ Method *clone_method_impl () const { return new Method (*this); } +}; + +// Item that supports visibility - abstract base class +class VisItem : public Item +{ + Visibility visibility; + std::vector outer_attrs; + +protected: + // Visibility constructor + VisItem (Visibility visibility, + std::vector outer_attrs = std::vector ()) + : visibility (std::move (visibility)), outer_attrs (std::move (outer_attrs)) + {} + + // Visibility copy constructor + VisItem (VisItem const &other) + : visibility (other.visibility), outer_attrs (other.outer_attrs) + {} + + // Overload assignment operator to clone + VisItem &operator= (VisItem const &other) + { + visibility = other.visibility; + outer_attrs = other.outer_attrs; + + return *this; + } + + // move constructors + VisItem (VisItem &&other) = default; + VisItem &operator= (VisItem &&other) = default; + +public: + /* Does the item have some kind of public visibility (non-default + * visibility)? */ + bool has_visibility () const { return visibility.is_public (); } + + std::string as_string () const override; + + // TODO: this mutable getter seems really dodgy. Think up better way. + Visibility &get_visibility () { return visibility; } + const Visibility &get_visibility () const { return visibility; } + + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } +}; + +// Rust module item - abstract base class +class Module : public VisItem +{ +public: + // Type of the current module. A module can be either loaded or unloaded, + // meaning that the items of the module can already be present or not. For + // example, the following module would be loaded: `mod foo { fn bar() {} }`. + // However, the module would be unloaded if it refers to an external file (i.e + // `mod foo;`) and then become loaded upon expansion. + enum ModuleKind + { + LOADED, + UNLOADED, + }; + + Identifier get_name () const { return module_name; } + +private: + Identifier module_name; + Location locus; + ModuleKind kind; + + // Name of the file including the module + std::string outer_filename; + // bool has_inner_attrs; + std::vector inner_attrs; + // bool has_items; + std::vector> items; + // Names of including inline modules (immediate parent is last in the list) + std::vector module_scope; + + // Filename the module refers to. Empty string on LOADED modules or if an + // error occured when dealing with UNLOADED modules + std::string module_file; + + void clone_items (const std::vector> &other_items) + { + items.reserve (other_items.size ()); + for (const auto &e : other_items) + items.push_back (e->clone_item ()); + } + +public: + // Returns whether the module has items in its body. + bool has_items () const { return !items.empty (); } + + // Returns whether the module has any inner attributes. + bool has_inner_attrs () const { return !inner_attrs.empty (); } + + // Unloaded module constructor + Module (Identifier module_name, Visibility visibility, + std::vector outer_attrs, Location locus, + std::string outer_filename, std::vector module_scope) + : VisItem (std::move (visibility), std::move (outer_attrs)), + module_name (module_name), locus (locus), kind (ModuleKind::UNLOADED), + outer_filename (outer_filename), inner_attrs (std::vector ()), + items (std::vector> ()), + module_scope (std::move (module_scope)) + {} + + // Loaded module constructor, with items + Module (Identifier name, Location locus, + std::vector> items, + Visibility visibility = Visibility::create_error (), + std::vector inner_attrs = std::vector (), + std::vector outer_attrs = std::vector ()) + : VisItem (std::move (visibility), std::move (outer_attrs)), + module_name (name), locus (locus), kind (ModuleKind::LOADED), + outer_filename (std::string ()), inner_attrs (std::move (inner_attrs)), + items (std::move (items)) + {} + + // Copy constructor with vector clone + Module (Module const &other) + : VisItem (other), module_name (other.module_name), locus (other.locus), + kind (other.kind), inner_attrs (other.inner_attrs), + module_scope (other.module_scope) + { + // We need to check whether we are copying a loaded module or an unloaded + // one. In the second case, clear the `items` vector. + if (other.kind == LOADED) + clone_items (other.items); + else + items.clear (); + } + + // Overloaded assignment operator with vector clone + Module &operator= (Module const &other) + { + VisItem::operator= (other); + + module_name = other.module_name; + locus = other.locus; + kind = other.kind; + inner_attrs = other.inner_attrs; + module_scope = other.module_scope; + + // Likewise, we need to clear the `items` vector in case the other module is + // unloaded + if (kind == LOADED) + clone_items (other.items); + else + items.clear (); + + return *this; + } + + // Search for the filename associated with an external module, storing it in + // module_file + void process_file_path (); + // Load the items contained in an external module + void load_items (); + + void accept_vis (ASTVisitor &vis) override; + + /* Override that runs the function recursively on all items contained within + * the module. */ + void add_crate_name (std::vector &names) const override; + + // Returns the kind of the module + enum ModuleKind get_kind () const { return kind; } + + // TODO: think of better way to do this - mutable getter seems dodgy + const std::vector &get_inner_attrs () const { return inner_attrs; } + std::vector &get_inner_attrs () { return inner_attrs; } + + const std::vector> &get_items () const { return items; } + std::vector> &get_items () { return items; } + + // move constructors + Module (Module &&other) = default; + Module &operator= (Module &&other) = default; + + std::string as_string () const override; + + Location get_locus () const override final { return locus; } + + // Invalid if name is empty, so base stripping on that. + void mark_for_strip () override { module_name = ""; } + bool is_marked_for_strip () const override { return module_name.empty (); } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + Module *clone_item_impl () const override { return new Module (*this); } +}; + +// Rust extern crate declaration AST node +class ExternCrate : public VisItem +{ + // this is either an identifier or "self", with self parsed to string + std::string referenced_crate; + // bool has_as_clause; + // AsClause as_clause; + // this is either an identifier or "_", with _ parsed to string + std::string as_clause_name; + + Location locus; + + /* e.g. + "extern crate foo as _" + "extern crate foo" + "extern crate std as cool_std" */ +public: + std::string as_string () const override; + + // Returns whether extern crate declaration has an as clause. + bool has_as_clause () const { return !as_clause_name.empty (); } + + /* Returns whether extern crate declaration references the current crate + * (i.e. self). */ + bool references_self () const { return referenced_crate == "self"; } + + // Constructor + ExternCrate (std::string referenced_crate, Visibility visibility, + std::vector outer_attrs, Location locus, + std::string as_clause_name = std::string ()) + : VisItem (std::move (visibility), std::move (outer_attrs)), + referenced_crate (std::move (referenced_crate)), + as_clause_name (std::move (as_clause_name)), locus (locus) + {} + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + const std::string &get_referenced_crate () const { return referenced_crate; } + const std::string &get_as_clause () const { return as_clause_name; } + + // Override that adds extern crate name in decl to passed list of names. + void add_crate_name (std::vector &names) const override + { + names.push_back (referenced_crate); + } + + // Invalid if crate name is empty, so base stripping on that. + void mark_for_strip () override { referenced_crate = ""; } + bool is_marked_for_strip () const override + { + return referenced_crate.empty (); + } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + ExternCrate *clone_item_impl () const override + { + return new ExternCrate (*this); + } +}; + +// The path-ish thing referred to in a use declaration - abstract base class +class UseTree +{ + Location locus; + +public: + enum Kind + { + Glob, + Rebind, + List, + }; + + virtual ~UseTree () {} + + // Overload assignment operator to clone + UseTree &operator= (UseTree const &other) + { + locus = other.locus; + + return *this; + } + + UseTree (const UseTree &other) = default; + + // move constructors + UseTree (UseTree &&other) = default; + UseTree &operator= (UseTree &&other) = default; + + // Unique pointer custom clone function + std::unique_ptr clone_use_tree () const + { + return std::unique_ptr (clone_use_tree_impl ()); + } + + virtual std::string as_string () const = 0; + virtual Kind get_kind () const = 0; + + Location get_locus () const { return locus; } + + virtual void accept_vis (ASTVisitor &vis) = 0; + +protected: + // Clone function implementation as pure virtual method + virtual UseTree *clone_use_tree_impl () const = 0; + + UseTree (Location locus) : locus (locus) {} +}; + +// Use tree with a glob (wildcard) operator +class UseTreeGlob : public UseTree +{ +public: + enum PathType + { + NO_PATH, + GLOBAL, + PATH_PREFIXED + }; + +private: + PathType glob_type; + SimplePath path; + +public: + UseTreeGlob (PathType glob_type, SimplePath path, Location locus) + : UseTree (locus), glob_type (glob_type), path (std::move (path)) + { + if (this->glob_type != PATH_PREFIXED) + { + // compiler implementation error if there is a path with a + // non-path-prefixed use tree glob + rust_assert (!has_path ()); + } + // TODO: do path-prefixed paths also have to have a path? If so, have an + // assert for that too. + } + + /* Returns whether has path. Should be made redundant by PathType + * PATH_PREFIXED. */ + bool has_path () const { return !path.is_empty (); } + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + Kind get_kind () const override { return Glob; } + + SimplePath get_path () const + { + rust_assert (has_path ()); + return path; + } + + /* TODO: find way to ensure only PATH_PREFIXED glob_type has path - factory + * methods? */ +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + UseTreeGlob *clone_use_tree_impl () const override + { + return new UseTreeGlob (*this); + } +}; + +// Use tree with a list of paths with a common prefix +class UseTreeList : public UseTree +{ +public: + enum PathType + { + NO_PATH, + GLOBAL, + PATH_PREFIXED + }; + +private: + PathType path_type; + SimplePath path; + + std::vector> trees; + +public: + UseTreeList (PathType path_type, SimplePath path, + std::vector> trees, Location locus) + : UseTree (locus), path_type (path_type), path (std::move (path)), + trees (std::move (trees)) + { + if (this->path_type != PATH_PREFIXED) + { + // compiler implementation error if there is a path with a + // non-path-prefixed use tree glob + rust_assert (!has_path ()); + } + // TODO: do path-prefixed paths also have to have a path? If so, have an + // assert for that too. + } + + // copy constructor with vector clone + UseTreeList (UseTreeList const &other) + : UseTree (other), path_type (other.path_type), path (other.path) + { + trees.reserve (other.trees.size ()); + for (const auto &e : other.trees) + trees.push_back (e->clone_use_tree ()); + } + + // overloaded assignment operator with vector clone + UseTreeList &operator= (UseTreeList const &other) + { + UseTree::operator= (other); + path_type = other.path_type; + path = other.path; + + trees.reserve (other.trees.size ()); + for (const auto &e : other.trees) + trees.push_back (e->clone_use_tree ()); + + return *this; + } + + // move constructors + UseTreeList (UseTreeList &&other) = default; + UseTreeList &operator= (UseTreeList &&other) = default; + + // Returns whether has path. Should be made redundant by path_type. + bool has_path () const { return !path.is_empty (); } + + // Returns whether has inner tree elements. + bool has_trees () const { return !trees.empty (); } + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + Kind get_kind () const override { return List; } + SimplePath get_path () const + { + rust_assert (has_path ()); + return path; + } + + const std::vector> &get_trees () const + { + return trees; + } + + // TODO: find way to ensure only PATH_PREFIXED path_type has path - factory + // methods? +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + UseTreeList *clone_use_tree_impl () const override + { + return new UseTreeList (*this); + } +}; + +// Use tree where it rebinds the module name as something else +class UseTreeRebind : public UseTree +{ +public: + enum NewBindType + { + NONE, + IDENTIFIER, + WILDCARD + }; + +private: + SimplePath path; + + NewBindType bind_type; + Identifier identifier; // only if NewBindType is IDENTIFIER + +public: + UseTreeRebind (NewBindType bind_type, SimplePath path, Location locus, + Identifier identifier = std::string ()) + : UseTree (locus), path (std::move (path)), bind_type (bind_type), + identifier (std::move (identifier)) + {} + + // Returns whether has path (this should always be true). + bool has_path () const { return !path.is_empty (); } + + // Returns whether has identifier (or, rather, is allowed to). + bool has_identifier () const { return bind_type == IDENTIFIER; } + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + Kind get_kind () const override { return Rebind; } + + SimplePath get_path () const + { + rust_assert (has_path ()); + return path; + } + + const Identifier &get_identifier () const + { + rust_assert (has_identifier ()); + return identifier; + } + + // TODO: find way to ensure only PATH_PREFIXED path_type has path - factory + // methods? +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + virtual UseTreeRebind *clone_use_tree_impl () const override + { + return new UseTreeRebind (*this); + } +}; + +// Rust use declaration (i.e. for modules) AST node +class UseDeclaration : public VisItem +{ + std::unique_ptr use_tree; + Location locus; + +public: + std::string as_string () const override; + + UseDeclaration (std::unique_ptr use_tree, Visibility visibility, + std::vector outer_attrs, Location locus) + : VisItem (std::move (visibility), std::move (outer_attrs)), + use_tree (std::move (use_tree)), locus (locus) + {} + + // Copy constructor with clone + UseDeclaration (UseDeclaration const &other) + : VisItem (other), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.use_tree != nullptr) + use_tree = other.use_tree->clone_use_tree (); + } + + // Overloaded assignment operator to clone + UseDeclaration &operator= (UseDeclaration const &other) + { + VisItem::operator= (other); + // visibility = other.visibility->clone_visibility(); + // outer_attrs = other.outer_attrs; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.use_tree != nullptr) + use_tree = other.use_tree->clone_use_tree (); + else + use_tree = nullptr; + + return *this; + } + + // move constructors + UseDeclaration (UseDeclaration &&other) = default; + UseDeclaration &operator= (UseDeclaration &&other) = default; + + Location get_locus () const override final { return locus; } + const std::unique_ptr &get_tree () const { return use_tree; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if use tree is null, so base stripping on that. + void mark_for_strip () override { use_tree = nullptr; } + bool is_marked_for_strip () const override { return use_tree == nullptr; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + UseDeclaration *clone_item_impl () const override + { + return new UseDeclaration (*this); + } +}; + +class LetStmt; + +// Rust function declaration AST node +class Function : public VisItem, public InherentImplItem, public TraitImplItem +{ + FunctionQualifiers qualifiers; + Identifier function_name; + std::vector> generic_params; + std::vector function_params; + std::unique_ptr return_type; + WhereClause where_clause; + std::unique_ptr function_body; + Location locus; + +public: + std::string as_string () const override; + + // Returns whether function has generic parameters. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether function has regular parameters. + bool has_function_params () const { return !function_params.empty (); } + + // Returns whether function has return type - if not, it is void. + bool has_return_type () const { return return_type != nullptr; } + + // Returns whether function has a where clause. + bool has_where_clause () const { return !where_clause.is_empty (); } + + // Mega-constructor with all possible fields + Function (Identifier function_name, FunctionQualifiers qualifiers, + std::vector> generic_params, + std::vector function_params, + std::unique_ptr return_type, WhereClause where_clause, + std::unique_ptr function_body, Visibility vis, + std::vector outer_attrs, Location locus) + : VisItem (std::move (vis), std::move (outer_attrs)), + qualifiers (std::move (qualifiers)), + function_name (std::move (function_name)), + generic_params (std::move (generic_params)), + function_params (std::move (function_params)), + return_type (std::move (return_type)), + where_clause (std::move (where_clause)), + function_body (std::move (function_body)), locus (locus) + {} + + // TODO: add constructor with less fields + + // Copy constructor with clone + Function (Function const &other) + : VisItem (other), qualifiers (other.qualifiers), + function_name (other.function_name), + function_params (other.function_params), + where_clause (other.where_clause), locus (other.locus) + { + // guard to prevent null dereference (always required) + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + + // guard to prevent null dereference (only required if error state) + if (other.function_body != nullptr) + function_body = other.function_body->clone_block_expr (); + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + } + + // Overloaded assignment operator to clone + Function &operator= (Function const &other) + { + VisItem::operator= (other); + function_name = other.function_name; + qualifiers = other.qualifiers; + function_params = other.function_params; + where_clause = other.where_clause; + // visibility = other.visibility->clone_visibility(); + // outer_attrs = other.outer_attrs; + locus = other.locus; + + // guard to prevent null dereference (always required) + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + + // guard to prevent null dereference (only required if error state) + if (other.function_body != nullptr) + function_body = other.function_body->clone_block_expr (); + else + function_body = nullptr; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; + } + + // move constructors + Function (Function &&other) = default; + Function &operator= (Function &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if block is null, so base stripping on that. + void mark_for_strip () override { function_body = nullptr; } + bool is_marked_for_strip () const override + { + return function_body == nullptr; + } + + std::vector &get_function_params () { return function_params; } + const std::vector &get_function_params () const + { + return function_params; + } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_definition () + { + rust_assert (function_body != nullptr); + return function_body; + } + + const FunctionQualifiers &get_qualifiers () const { return qualifiers; } + + Identifier get_function_name () const { return function_name; } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () { return where_clause; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; + } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + Function *clone_item_impl () const override { return new Function (*this); } + + /* Use covariance to implement clone function as returning this object + * rather than base */ + Function *clone_inherent_impl_item_impl () const override + { + return new Function (*this); + } + + /* Use covariance to implement clone function as returning this object + * rather than base */ + Function *clone_trait_impl_item_impl () const override + { + return new Function (*this); + } +}; + +// Rust type alias (i.e. typedef) AST node +class TypeAlias : public VisItem, public TraitImplItem +{ + Identifier new_type_name; + + // bool has_generics; + // Generics generic_params; + std::vector> generic_params; // inlined + + // bool has_where_clause; + WhereClause where_clause; + + std::unique_ptr existing_type; + + Location locus; + +public: + std::string as_string () const override; + + // Returns whether type alias has generic parameters. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether type alias has a where clause. + bool has_where_clause () const { return !where_clause.is_empty (); } + + // Mega-constructor with all possible fields + TypeAlias (Identifier new_type_name, + std::vector> generic_params, + WhereClause where_clause, std::unique_ptr existing_type, + Visibility vis, std::vector outer_attrs, Location locus) + : VisItem (std::move (vis), std::move (outer_attrs)), + new_type_name (std::move (new_type_name)), + generic_params (std::move (generic_params)), + where_clause (std::move (where_clause)), + existing_type (std::move (existing_type)), locus (locus) + {} + + // Copy constructor + TypeAlias (TypeAlias const &other) + : VisItem (other), new_type_name (other.new_type_name), + where_clause (other.where_clause), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.existing_type != nullptr) + existing_type = other.existing_type->clone_type (); + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + } + + // Overloaded assignment operator to clone + TypeAlias &operator= (TypeAlias const &other) + { + VisItem::operator= (other); + new_type_name = other.new_type_name; + where_clause = other.where_clause; + // visibility = other.visibility->clone_visibility(); + // outer_attrs = other.outer_attrs; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.existing_type != nullptr) + existing_type = other.existing_type->clone_type (); + else + existing_type = nullptr; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; + } + + // move constructors + TypeAlias (TypeAlias &&other) = default; + TypeAlias &operator= (TypeAlias &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if existing type is null, so base stripping on that. + void mark_for_strip () override { existing_type = nullptr; } + bool is_marked_for_strip () const override + { + return existing_type == nullptr; + } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () { return where_clause; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type_aliased () + { + rust_assert (existing_type != nullptr); + return existing_type; + } + + Identifier get_new_type_name () const { return new_type_name; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + TypeAlias *clone_item_impl () const override { return new TypeAlias (*this); } + + /* Use covariance to implement clone function as returning this object + * rather than base */ + TypeAlias *clone_trait_impl_item_impl () const override + { + return new TypeAlias (*this); + } +}; + +// Rust base struct declaration AST node - abstract base class +class Struct : public VisItem +{ +protected: + // protected to enable access by derived classes - allows better as_string + Identifier struct_name; + + // bool has_generics; + // Generics generic_params; + std::vector> generic_params; // inlined + + // bool has_where_clause; + WhereClause where_clause; + +private: + Location locus; + +public: + // Returns whether struct has generic parameters. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether struct has a where clause. + bool has_where_clause () const { return !where_clause.is_empty (); } + + Location get_locus () const override final { return locus; } + + // Invalid if name is empty, so base stripping on that. + void mark_for_strip () override { struct_name = ""; } + bool is_marked_for_strip () const override { return struct_name.empty (); } + + Identifier get_struct_name () const { return struct_name; } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () { return where_clause; } + + Identifier get_identifier () const { return struct_name; } + +protected: + Struct (Identifier struct_name, + std::vector> generic_params, + WhereClause where_clause, Visibility vis, Location locus, + std::vector outer_attrs = std::vector ()) + : VisItem (std::move (vis), std::move (outer_attrs)), + struct_name (std::move (struct_name)), + generic_params (std::move (generic_params)), + where_clause (std::move (where_clause)), locus (locus) + {} + + // Copy constructor with vector clone + Struct (Struct const &other) + : VisItem (other), struct_name (other.struct_name), + where_clause (other.where_clause), locus (other.locus) + { + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + } + + // Overloaded assignment operator with vector clone + Struct &operator= (Struct const &other) + { + VisItem::operator= (other); + struct_name = other.struct_name; + where_clause = other.where_clause; + locus = other.locus; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; + } + + // move constructors + Struct (Struct &&other) = default; + Struct &operator= (Struct &&other) = default; +}; + +// A single field in a struct +struct StructField +{ +private: + // bool has_outer_attributes; + std::vector outer_attrs; + + // bool has_visibility; + Visibility visibility; + + Identifier field_name; + std::unique_ptr field_type; + + NodeId node_id; + + Location locus; + +public: + // Returns whether struct field has any outer attributes. + bool has_outer_attributes () const { return !outer_attrs.empty (); } + + // Returns whether struct field has a non-private (non-default) visibility. + bool has_visibility () const { return !visibility.is_error (); } + + StructField (Identifier field_name, std::unique_ptr field_type, + Visibility vis, Location locus, + std::vector outer_attrs = std::vector ()) + : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)), + field_name (std::move (field_name)), field_type (std::move (field_type)), + node_id (Analysis::Mappings::get ()->get_next_node_id ()), locus (locus) + {} + + // Copy constructor + StructField (StructField const &other) + : outer_attrs (other.outer_attrs), visibility (other.visibility), + field_name (other.field_name), node_id (other.node_id), + locus (other.locus) + { + // guard to prevent null dereference + if (other.field_type != nullptr) + field_type = other.field_type->clone_type (); + } + + ~StructField () = default; + + // Overloaded assignment operator to clone + StructField &operator= (StructField const &other) + { + field_name = other.field_name; + visibility = other.visibility; + outer_attrs = other.outer_attrs; + node_id = other.node_id; + + // guard to prevent null dereference + if (other.field_type != nullptr) + field_type = other.field_type->clone_type (); + else + field_type = nullptr; + + return *this; + } + + // move constructors + StructField (StructField &&other) = default; + StructField &operator= (StructField &&other) = default; + + // Returns whether struct field is in an error state. + bool is_error () const + { + return field_name.empty () && field_type == nullptr; + // this should really be an or since neither are allowed + } + + // Creates an error state struct field. + static StructField create_error () + { + return StructField (std::string (""), nullptr, Visibility::create_error (), + Location ()); + } + + std::string as_string () const; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + Identifier get_field_name () const { return field_name; } + + Location get_locus () const { return locus; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_field_type () + { + rust_assert (field_type != nullptr); + return field_type; + } + + const Visibility &get_visibility () const { return visibility; } + + NodeId get_node_id () const { return node_id; } +}; + +// Rust struct declaration with true struct type AST node +class StructStruct : public Struct +{ + std::vector fields; + bool is_unit; + +public: + std::string as_string () const override; + + // Mega-constructor with all possible fields + StructStruct (std::vector fields, Identifier struct_name, + std::vector> generic_params, + WhereClause where_clause, bool is_unit, Visibility vis, + std::vector outer_attrs, Location locus) + : Struct (std::move (struct_name), std::move (generic_params), + std::move (where_clause), std::move (vis), locus, + std::move (outer_attrs)), + fields (std::move (fields)), is_unit (is_unit) + {} + + // Unit struct constructor + StructStruct (Identifier struct_name, + std::vector> generic_params, + WhereClause where_clause, Visibility vis, + std::vector outer_attrs, Location locus) + : Struct (std::move (struct_name), std::move (generic_params), + std::move (where_clause), std::move (vis), locus, + std::move (outer_attrs)), + is_unit (true) + {} + + /* Returns whether the struct is a unit struct - struct defined without + * fields. This is important because it also means an implicit constant of its + * type is defined. */ + bool is_unit_struct () const { return is_unit; } + + void accept_vis (ASTVisitor &vis) override; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_fields () { return fields; } + const std::vector &get_fields () const { return fields; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + StructStruct *clone_item_impl () const override + { + return new StructStruct (*this); + } +}; + +// A single field in a tuple +struct TupleField +{ +private: + // bool has_outer_attributes; + std::vector outer_attrs; + + // bool has_visibility; + Visibility visibility; + + std::unique_ptr field_type; + + NodeId node_id; + + Location locus; + +public: + // Returns whether tuple field has outer attributes. + bool has_outer_attributes () const { return !outer_attrs.empty (); } + + /* Returns whether tuple field has a non-default visibility (i.e. a public + * one) */ + bool has_visibility () const { return !visibility.is_error (); } + + // Complete constructor + TupleField (std::unique_ptr field_type, Visibility vis, Location locus, + std::vector outer_attrs = std::vector ()) + : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)), + field_type (std::move (field_type)), + node_id (Analysis::Mappings::get ()->get_next_node_id ()), locus (locus) + {} + + // Copy constructor with clone + TupleField (TupleField const &other) + : outer_attrs (other.outer_attrs), visibility (other.visibility), + node_id (other.node_id), locus (other.locus) + { + // guard to prevent null dereference (only required if error) + if (other.field_type != nullptr) + field_type = other.field_type->clone_type (); + } + + ~TupleField () = default; + + // Overloaded assignment operator to clone + TupleField &operator= (TupleField const &other) + { + visibility = other.visibility; + outer_attrs = other.outer_attrs; + node_id = other.node_id; + locus = other.locus; + + // guard to prevent null dereference (only required if error) + if (other.field_type != nullptr) + field_type = other.field_type->clone_type (); + else + field_type = nullptr; + + return *this; + } + + // move constructors + TupleField (TupleField &&other) = default; + TupleField &operator= (TupleField &&other) = default; + + // Returns whether tuple field is in an error state. + bool is_error () const { return field_type == nullptr; } + + // Creates an error state tuple field. + static TupleField create_error () + { + return TupleField (nullptr, Visibility::create_error (), Location ()); + } + + std::string as_string () const; + + NodeId get_node_id () const { return node_id; } + + const Visibility &get_visibility () const { return visibility; } + + Location get_locus () const { return locus; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_field_type () + { + rust_assert (field_type != nullptr); + return field_type; + } +}; + +// Rust tuple declared using struct keyword AST node +class TupleStruct : public Struct +{ + std::vector fields; + +public: + std::string as_string () const override; + + // Mega-constructor with all possible fields + TupleStruct (std::vector fields, Identifier struct_name, + std::vector> generic_params, + WhereClause where_clause, Visibility vis, + std::vector outer_attrs, Location locus) + : Struct (std::move (struct_name), std::move (generic_params), + std::move (where_clause), std::move (vis), locus, + std::move (outer_attrs)), + fields (std::move (fields)) + {} + + void accept_vis (ASTVisitor &vis) override; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_fields () { return fields; } + const std::vector &get_fields () const { return fields; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + TupleStruct *clone_item_impl () const override + { + return new TupleStruct (*this); + } +}; + +/* An item used in an "enum" tagged union - not abstract: base represents a + * name-only enum. EnumItems (variants) syntactically allow a Visibility + * annotation. */ +class EnumItem : public VisItem +{ + Identifier variant_name; + + Location locus; + +public: + virtual ~EnumItem () {} + + EnumItem (Identifier variant_name, Visibility vis, + std::vector outer_attrs, Location locus) + : VisItem (std::move (vis), std::move (outer_attrs)), + variant_name (std::move (variant_name)), locus (locus) + {} + + // Unique pointer custom clone function + std::unique_ptr clone_enum_item () const + { + return std::unique_ptr (clone_item_impl ()); + } + + virtual std::string as_string () const; + + // not pure virtual as not abstract + virtual void accept_vis (ASTVisitor &vis); + + Location get_locus () const { return locus; } + + Identifier get_identifier () const { return variant_name; } + + // Based on idea that name is never empty. + void mark_for_strip () { variant_name = ""; } + bool is_marked_for_strip () const { return variant_name.empty (); } + +protected: + EnumItem *clone_item_impl () const override { return new EnumItem (*this); } +}; + +// A tuple item used in an "enum" tagged union +class EnumItemTuple : public EnumItem +{ + // bool has_tuple_fields; + std::vector tuple_fields; + +public: + // Returns whether tuple enum item has tuple fields. + bool has_tuple_fields () const { return !tuple_fields.empty (); } + + EnumItemTuple (Identifier variant_name, Visibility vis, + std::vector tuple_fields, + std::vector outer_attrs, Location locus) + : EnumItem (std::move (variant_name), std::move (vis), + std::move (outer_attrs), locus), + tuple_fields (std::move (tuple_fields)) + {} + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_tuple_fields () { return tuple_fields; } + const std::vector &get_tuple_fields () const + { + return tuple_fields; + } + +protected: + // Clone function implementation as (not pure) virtual method + EnumItemTuple *clone_item_impl () const override + { + return new EnumItemTuple (*this); + } +}; + +// A struct item used in an "enum" tagged union +class EnumItemStruct : public EnumItem +{ + // bool has_struct_fields; + std::vector struct_fields; + +public: + // Returns whether struct enum item has struct fields. + bool has_struct_fields () const { return !struct_fields.empty (); } + + EnumItemStruct (Identifier variant_name, Visibility vis, + std::vector struct_fields, + std::vector outer_attrs, Location locus) + : EnumItem (std::move (variant_name), std::move (vis), + std::move (outer_attrs), locus), + struct_fields (std::move (struct_fields)) + {} + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_struct_fields () { return struct_fields; } + const std::vector &get_struct_fields () const + { + return struct_fields; + } + +protected: + // Clone function implementation as (not pure) virtual method + EnumItemStruct *clone_item_impl () const override + { + return new EnumItemStruct (*this); + } +}; + +// A discriminant (numbered enum) item used in an "enum" tagged union +class EnumItemDiscriminant : public EnumItem +{ + std::unique_ptr expression; + +public: + EnumItemDiscriminant (Identifier variant_name, Visibility vis, + std::unique_ptr expr, + std::vector outer_attrs, Location locus) + : EnumItem (std::move (variant_name), std::move (vis), + std::move (outer_attrs), locus), + expression (std::move (expr)) + {} + + // Copy constructor with clone + EnumItemDiscriminant (EnumItemDiscriminant const &other) + : EnumItem (other), expression (other.expression->clone_expr ()) + {} + + // Overloaded assignment operator to clone + EnumItemDiscriminant &operator= (EnumItemDiscriminant const &other) + { + EnumItem::operator= (other); + expression = other.expression->clone_expr (); + // variant_name = other.variant_name; + // outer_attrs = other.outer_attrs; + + return *this; + } + + // move constructors + EnumItemDiscriminant (EnumItemDiscriminant &&other) = default; + EnumItemDiscriminant &operator= (EnumItemDiscriminant &&other) = default; + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_expr () + { + rust_assert (expression != nullptr); + return expression; + } + +protected: + // Clone function implementation as (not pure) virtual method + EnumItemDiscriminant *clone_item_impl () const override + { + return new EnumItemDiscriminant (*this); + } +}; + +// AST node for Rust "enum" - tagged union +class Enum : public VisItem +{ + Identifier enum_name; + + // bool has_generics; + // Generics generic_params; + std::vector> generic_params; // inlined + + // bool has_where_clause; + WhereClause where_clause; + + std::vector> items; + + Location locus; + +public: + std::string as_string () const override; + + // Returns whether "enum" has generic parameters. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether "enum" has a where clause. + bool has_where_clause () const { return !where_clause.is_empty (); } + + /* Returns whether enum is a "zero-variant" (no possible variant) enum, + * which cannot be instantiated. */ + bool is_zero_variant () const { return items.empty (); } + + // Mega-constructor + Enum (Identifier enum_name, Visibility vis, + std::vector> generic_params, + WhereClause where_clause, std::vector> items, + std::vector outer_attrs, Location locus) + : VisItem (std::move (vis), std::move (outer_attrs)), + enum_name (std::move (enum_name)), + generic_params (std::move (generic_params)), + where_clause (std::move (where_clause)), items (std::move (items)), + locus (locus) + {} + + // TODO: constructor with less arguments + + // Copy constructor with vector clone + Enum (Enum const &other) + : VisItem (other), enum_name (other.enum_name), + where_clause (other.where_clause), locus (other.locus) + { + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_enum_item ()); + } + + // Overloaded assignment operator with vector clone + Enum &operator= (Enum const &other) + { + VisItem::operator= (other); + enum_name = other.enum_name; + where_clause = other.where_clause; + locus = other.locus; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_enum_item ()); + + return *this; + } + + // Move constructors + Enum (Enum &&other) = default; + Enum &operator= (Enum &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + Identifier get_identifier () const { return enum_name; } + + // Invalid if name is empty, so base stripping on that. + void mark_for_strip () override { enum_name = ""; } + bool is_marked_for_strip () const override { return enum_name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector> &get_variants () { return items; } + const std::vector> &get_variants () const + { + return items; + } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () { return where_clause; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + Enum *clone_item_impl () const override { return new Enum (*this); } +}; + +// Rust untagged union used for C compat AST node +class Union : public VisItem +{ + Identifier union_name; + + // bool has_generics; + // Generics generic_params; + std::vector> generic_params; // inlined + + // bool has_where_clause; + WhereClause where_clause; + + std::vector variants; + + Location locus; + +public: + std::string as_string () const override; + + // Returns whether union has generic params. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether union has where clause. + bool has_where_clause () const { return !where_clause.is_empty (); } + + Union (Identifier union_name, Visibility vis, + std::vector> generic_params, + WhereClause where_clause, std::vector variants, + std::vector outer_attrs, Location locus) + : VisItem (std::move (vis), std::move (outer_attrs)), + union_name (std::move (union_name)), + generic_params (std::move (generic_params)), + where_clause (std::move (where_clause)), variants (std::move (variants)), + locus (locus) + {} + + // copy constructor with vector clone + Union (Union const &other) + : VisItem (other), union_name (other.union_name), + where_clause (other.where_clause), variants (other.variants), + locus (other.locus) + { + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + } + + // overloaded assignment operator with vector clone + Union &operator= (Union const &other) + { + VisItem::operator= (other); + union_name = other.union_name; + where_clause = other.where_clause; + variants = other.variants; + locus = other.locus; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; + } + + // move constructors + Union (Union &&other) = default; + Union &operator= (Union &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if name is empty, so base stripping on that. + void mark_for_strip () override { union_name = ""; } + bool is_marked_for_strip () const override { return union_name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_variants () { return variants; } + const std::vector &get_variants () const { return variants; } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () { return where_clause; } + + Identifier get_identifier () const { return union_name; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + Union *clone_item_impl () const override { return new Union (*this); } +}; + +/* "Constant item" AST node - used for constant, compile-time expressions + * within module scope (like constexpr) */ +class ConstantItem : public VisItem, + public InherentImplItem, + public TraitImplItem +{ + // either has an identifier or "_" - maybe handle in identifier? + // bool identifier_is_underscore; + // if no identifier declared, identifier will be "_" + std::string identifier; + + std::unique_ptr type; + std::unique_ptr const_expr; + + Location locus; + +public: + std::string as_string () const override; + + ConstantItem (std::string ident, Visibility vis, std::unique_ptr type, + std::unique_ptr const_expr, + std::vector outer_attrs, Location locus) + : VisItem (std::move (vis), std::move (outer_attrs)), + identifier (std::move (ident)), type (std::move (type)), + const_expr (std::move (const_expr)), locus (locus) + {} + + ConstantItem (ConstantItem const &other) + : VisItem (other), identifier (other.identifier), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.type != nullptr) + type = other.type->clone_type (); + if (other.const_expr != nullptr) + const_expr = other.const_expr->clone_expr (); + } + + // Overload assignment operator to clone + ConstantItem &operator= (ConstantItem const &other) + { + VisItem::operator= (other); + identifier = other.identifier; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + if (other.const_expr != nullptr) + const_expr = other.const_expr->clone_expr (); + else + const_expr = nullptr; + + return *this; + } + + // move constructors + ConstantItem (ConstantItem &&other) = default; + ConstantItem &operator= (ConstantItem &&other) = default; + + /* Returns whether constant item is an "unnamed" (wildcard underscore used + * as identifier) constant. */ + bool is_unnamed () const { return identifier == "_"; } + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if type or expression are null, so base stripping on that. + void mark_for_strip () override + { + type = nullptr; + const_expr = nullptr; + } + bool is_marked_for_strip () const override + { + return type == nullptr && const_expr == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_expr () + { + rust_assert (const_expr != nullptr); + return const_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type () + { + rust_assert (type != nullptr); + return type; + } + + std::string get_identifier () const { return identifier; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + ConstantItem *clone_item_impl () const override + { + return new ConstantItem (*this); + } + + /* Use covariance to implement clone function as returning this object + * rather than base */ + ConstantItem *clone_inherent_impl_item_impl () const override + { + return new ConstantItem (*this); + } + + /* Use covariance to implement clone function as returning this object + * rather than base */ + ConstantItem *clone_trait_impl_item_impl () const override + { + return new ConstantItem (*this); + } +}; + +/* Static item AST node - items within module scope with fixed storage + * duration? */ +class StaticItem : public VisItem +{ + bool has_mut; + Identifier name; + std::unique_ptr type; + std::unique_ptr expr; + Location locus; + +public: + std::string as_string () const override; + + StaticItem (Identifier name, bool is_mut, std::unique_ptr type, + std::unique_ptr expr, Visibility vis, + std::vector outer_attrs, Location locus) + : VisItem (std::move (vis), std::move (outer_attrs)), has_mut (is_mut), + name (std::move (name)), type (std::move (type)), expr (std::move (expr)), + locus (locus) + {} + + // Copy constructor with clone + StaticItem (StaticItem const &other) + : VisItem (other), has_mut (other.has_mut), name (other.name), + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.type != nullptr) + type = other.type->clone_type (); + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + } + + // Overloaded assignment operator to clone + StaticItem &operator= (StaticItem const &other) + { + VisItem::operator= (other); + name = other.name; + has_mut = other.has_mut; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + else + expr = nullptr; + + return *this; + } + + // move constructors + StaticItem (StaticItem &&other) = default; + StaticItem &operator= (StaticItem &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if type or expression are null, so base stripping on that. + void mark_for_strip () override + { + type = nullptr; + expr = nullptr; + } + bool is_marked_for_strip () const override + { + return type == nullptr && expr == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_expr () + { + rust_assert (expr != nullptr); + return expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type () + { + rust_assert (type != nullptr); + return type; + } + + bool is_mutable () const { return has_mut; } + + Identifier get_identifier () const { return name; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + StaticItem *clone_item_impl () const override + { + return new StaticItem (*this); + } +}; + +// Function declaration in traits +struct TraitFunctionDecl +{ +private: + // TODO: delete and replace with Function decl item? no as no body in this. + FunctionQualifiers qualifiers; + Identifier function_name; + + // bool has_generics; + // Generics generic_params; + std::vector> generic_params; // inlined + + // bool has_params; + // FunctionParams function_params; + std::vector function_params; // inlined + + // bool has_return_type; + std::unique_ptr return_type; + + // bool has_where_clause; + WhereClause where_clause; + + // should this store location info? + +public: + // Returns whether function decl has generic parameters. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether function decl has regular parameters. + bool has_params () const { return !function_params.empty (); } + + // Returns whether function has return type (otherwise is void). + bool has_return_type () const { return return_type != nullptr; } + + // Returns whether function has a where clause. + bool has_where_clause () const { return !where_clause.is_empty (); } + + Identifier get_identifier () const { return function_name; } + + // Mega-constructor + TraitFunctionDecl (Identifier function_name, FunctionQualifiers qualifiers, + std::vector> generic_params, + std::vector function_params, + std::unique_ptr return_type, + WhereClause where_clause) + : qualifiers (std::move (qualifiers)), + function_name (std::move (function_name)), + generic_params (std::move (generic_params)), + function_params (std::move (function_params)), + return_type (std::move (return_type)), + where_clause (std::move (where_clause)) + {} + + // Copy constructor with clone + TraitFunctionDecl (TraitFunctionDecl const &other) + : qualifiers (other.qualifiers), function_name (other.function_name), + function_params (other.function_params), where_clause (other.where_clause) + { + // guard to prevent nullptr dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + } + + ~TraitFunctionDecl () = default; + + // Overloaded assignment operator with clone + TraitFunctionDecl &operator= (TraitFunctionDecl const &other) + { + function_name = other.function_name; + qualifiers = other.qualifiers; + function_params = other.function_params; + where_clause = other.where_clause; + + // guard to prevent nullptr dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; + } + + // move constructors + TraitFunctionDecl (TraitFunctionDecl &&other) = default; + TraitFunctionDecl &operator= (TraitFunctionDecl &&other) = default; + + std::string as_string () const; + + // Invalid if function name is empty, so base stripping on that. + void mark_for_strip () { function_name = ""; } + bool is_marked_for_strip () const { return function_name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_function_params () { return function_params; } + const std::vector &get_function_params () const + { + return function_params; + } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_return_type () { return return_type; } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () { return where_clause; } + + FunctionQualifiers get_qualifiers () { return qualifiers; } +}; + +// Actual trait item function declaration within traits +class TraitItemFunc : public TraitItem +{ + std::vector outer_attrs; + TraitFunctionDecl decl; + std::unique_ptr block_expr; + Location locus; + +public: + // Returns whether function has a definition or is just a declaration. + bool has_definition () const { return block_expr != nullptr; } + + TraitItemFunc (TraitFunctionDecl decl, std::unique_ptr block_expr, + std::vector outer_attrs, Location locus) + : TraitItem (), outer_attrs (std::move (outer_attrs)), + decl (std::move (decl)), block_expr (std::move (block_expr)), + locus (locus) + {} + + // Copy constructor with clone + TraitItemFunc (TraitItemFunc const &other) + : outer_attrs (other.outer_attrs), decl (other.decl), locus (other.locus) + { + node_id = other.node_id; + + // guard to prevent null dereference + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + } + + // Overloaded assignment operator to clone + TraitItemFunc &operator= (TraitItemFunc const &other) + { + TraitItem::operator= (other); + outer_attrs = other.outer_attrs; + decl = other.decl; + locus = other.locus; + node_id = other.node_id; + + // guard to prevent null dereference + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + else + block_expr = nullptr; + + return *this; + } + + // move constructors + TraitItemFunc (TraitItemFunc &&other) = default; + TraitItemFunc &operator= (TraitItemFunc &&other) = default; + + std::string as_string () const override; + + Location get_locus () const { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if trait decl is empty, so base stripping on that. + void mark_for_strip () override { decl.mark_for_strip (); } + bool is_marked_for_strip () const override + { + return decl.is_marked_for_strip (); + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_definition () { return block_expr; } + + // TODO: is this better? Or is a "vis_block" better? + TraitFunctionDecl &get_trait_function_decl () + { + // TODO: maybe only allow access if not marked for strip? + return decl; + } + +protected: + // Clone function implementation as (not pure) virtual method + TraitItemFunc *clone_trait_item_impl () const override + { + return new TraitItemFunc (*this); + } +}; + +// Method declaration within traits +struct TraitMethodDecl +{ +private: + // TODO: delete and replace with Function decl item? no as no body. + FunctionQualifiers qualifiers; + Identifier function_name; + + // bool has_generics; + // Generics generic_params; + std::vector> generic_params; // inlined + + SelfParam self_param; + + // bool has_params; + // FunctionParams function_params; + std::vector function_params; // inlined + + // bool has_return_type; + std::unique_ptr return_type; + + // bool has_where_clause; + WhereClause where_clause; + + // should this store location info? + +public: + // Returns whether method decl has generic parameters. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether method decl has regular parameters. + bool has_params () const { return !function_params.empty (); } + + // Returns whether method has return type (otherwise is void). + bool has_return_type () const { return return_type != nullptr; } + + // Returns whether method has a where clause. + bool has_where_clause () const { return !where_clause.is_empty (); } + + Identifier get_identifier () const { return function_name; } + + // Mega-constructor + TraitMethodDecl (Identifier function_name, FunctionQualifiers qualifiers, + std::vector> generic_params, + SelfParam self_param, + std::vector function_params, + std::unique_ptr return_type, WhereClause where_clause) + : qualifiers (std::move (qualifiers)), + function_name (std::move (function_name)), + generic_params (std::move (generic_params)), + self_param (std::move (self_param)), + function_params (std::move (function_params)), + return_type (std::move (return_type)), + where_clause (std::move (where_clause)) + {} + + // Copy constructor with clone + TraitMethodDecl (TraitMethodDecl const &other) + : qualifiers (other.qualifiers), function_name (other.function_name), + self_param (other.self_param), function_params (other.function_params), + where_clause (other.where_clause) + { + // guard to prevent nullptr dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + } + + ~TraitMethodDecl () = default; + + // Overloaded assignment operator with clone + TraitMethodDecl &operator= (TraitMethodDecl const &other) + { + function_name = other.function_name; + qualifiers = other.qualifiers; + self_param = other.self_param; + function_params = other.function_params; + where_clause = other.where_clause; + + // guard to prevent nullptr dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; + } + + // move constructors + TraitMethodDecl (TraitMethodDecl &&other) = default; + TraitMethodDecl &operator= (TraitMethodDecl &&other) = default; + + std::string as_string () const; + + // Invalid if method name is empty, so base stripping on that. + void mark_for_strip () { function_name = ""; } + bool is_marked_for_strip () const { return function_name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_function_params () { return function_params; } + const std::vector &get_function_params () const + { + return function_params; + } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_return_type () { return return_type; } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () { return where_clause; } + + SelfParam &get_self_param () { return self_param; } + const SelfParam &get_self_param () const { return self_param; } + + FunctionQualifiers get_qualifiers () { return qualifiers; } +}; + +// Actual trait item method declaration within traits +class TraitItemMethod : public TraitItem +{ + std::vector outer_attrs; + TraitMethodDecl decl; + std::unique_ptr block_expr; + Location locus; + +public: + // Returns whether method has a definition or is just a declaration. + bool has_definition () const { return block_expr != nullptr; } + + TraitItemMethod (TraitMethodDecl decl, std::unique_ptr block_expr, + std::vector outer_attrs, Location locus) + : TraitItem (), outer_attrs (std::move (outer_attrs)), + decl (std::move (decl)), block_expr (std::move (block_expr)), + locus (locus) + {} + + // Copy constructor with clone + TraitItemMethod (TraitItemMethod const &other) + : outer_attrs (other.outer_attrs), decl (other.decl), locus (other.locus) + { + node_id = other.node_id; + + // guard to prevent null dereference + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + } + + // Overloaded assignment operator to clone + TraitItemMethod &operator= (TraitItemMethod const &other) + { + TraitItem::operator= (other); + outer_attrs = other.outer_attrs; + decl = other.decl; + locus = other.locus; + node_id = other.node_id; + + // guard to prevent null dereference + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + else + block_expr = nullptr; + + return *this; + } + + // move constructors + TraitItemMethod (TraitItemMethod &&other) = default; + TraitItemMethod &operator= (TraitItemMethod &&other) = default; + + std::string as_string () const override; + + Location get_locus () const { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if trait decl is empty, so base stripping on that. + void mark_for_strip () override { decl.mark_for_strip (); } + bool is_marked_for_strip () const override + { + return decl.is_marked_for_strip (); + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + TraitMethodDecl &get_trait_method_decl () + { + // TODO: maybe only allow access if not marked for strip? + return decl; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_definition () { return block_expr; } + +protected: + // Clone function implementation as (not pure) virtual method + TraitItemMethod *clone_trait_item_impl () const override + { + return new TraitItemMethod (*this); + } +}; + +// Constant item within traits +class TraitItemConst : public TraitItem +{ + std::vector outer_attrs; + Identifier name; + std::unique_ptr type; + + // bool has_expression; + std::unique_ptr expr; + + Location locus; + +public: + // Whether the constant item has an associated expression. + bool has_expression () const { return expr != nullptr; } + + TraitItemConst (Identifier name, std::unique_ptr type, + std::unique_ptr expr, + std::vector outer_attrs, Location locus) + : TraitItem (), outer_attrs (std::move (outer_attrs)), + name (std::move (name)), type (std::move (type)), expr (std::move (expr)), + locus (locus) + {} + + // Copy constructor with clones + TraitItemConst (TraitItemConst const &other) + : outer_attrs (other.outer_attrs), name (other.name), locus (other.locus) + { + node_id = other.node_id; + + // guard to prevent null dereference + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + + // guard to prevent null dereference (only for error state) + if (other.type != nullptr) + type = other.type->clone_type (); + } + + // Overloaded assignment operator to clone + TraitItemConst &operator= (TraitItemConst const &other) + { + TraitItem::operator= (other); + outer_attrs = other.outer_attrs; + name = other.name; + locus = other.locus; + node_id = other.node_id; + + // guard to prevent null dereference + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + else + expr = nullptr; + + // guard to prevent null dereference (only for error state) + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + + return *this; + } + + // move constructors + TraitItemConst (TraitItemConst &&other) = default; + TraitItemConst &operator= (TraitItemConst &&other) = default; + + std::string as_string () const override; + + Location get_locus () const { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if type is null, so base stripping on that. + void mark_for_strip () override { type = nullptr; } + bool is_marked_for_strip () const override { return type == nullptr; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + bool has_expr () const { return expr != nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_expr () + { + rust_assert (has_expr ()); + return expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type () + { + rust_assert (type != nullptr); + return type; + } + + Identifier get_identifier () const { return name; } + +protected: + // Clone function implementation as (not pure) virtual method + TraitItemConst *clone_trait_item_impl () const override + { + return new TraitItemConst (*this); + } +}; + +// Type items within traits +class TraitItemType : public TraitItem +{ + std::vector outer_attrs; + + Identifier name; + + // bool has_type_param_bounds; + // TypeParamBounds type_param_bounds; + std::vector> + type_param_bounds; // inlined form + + Location locus; + +public: + // Returns whether trait item type has type param bounds. + bool has_type_param_bounds () const { return !type_param_bounds.empty (); } + + TraitItemType (Identifier name, + std::vector> type_param_bounds, + std::vector outer_attrs, Location locus) + : TraitItem (), outer_attrs (std::move (outer_attrs)), + name (std::move (name)), + type_param_bounds (std::move (type_param_bounds)), locus (locus) + {} + + // Copy constructor with vector clone + TraitItemType (TraitItemType const &other) + : outer_attrs (other.outer_attrs), name (other.name), locus (other.locus) + { + node_id = other.node_id; + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + } + + // Overloaded assignment operator with vector clone + TraitItemType &operator= (TraitItemType const &other) + { + TraitItem::operator= (other); + outer_attrs = other.outer_attrs; + name = other.name; + locus = other.locus; + node_id = other.node_id; + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + return *this; + } + + // default move constructors + TraitItemType (TraitItemType &&other) = default; + TraitItemType &operator= (TraitItemType &&other) = default; + + std::string as_string () const override; + + Location get_locus () const { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if name is empty, so base stripping on that. + void mark_for_strip () override { name = ""; } + bool is_marked_for_strip () const override { return name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + // TODO: mutable getter seems kinda dodgy + std::vector> &get_type_param_bounds () + { + return type_param_bounds; + } + const std::vector> & + get_type_param_bounds () const + { + return type_param_bounds; + } + + Identifier get_identifier () const { return name; } + +protected: + // Clone function implementation as (not pure) virtual method + TraitItemType *clone_trait_item_impl () const override + { + return new TraitItemType (*this); + } +}; + +// Rust trait item declaration AST node +class Trait : public VisItem +{ + bool has_unsafe; + Identifier name; + std::vector> generic_params; + std::vector> type_param_bounds; + WhereClause where_clause; + std::vector inner_attrs; + std::vector> trait_items; + Location locus; + +public: + std::string as_string () const override; + + // Returns whether trait has generic parameters. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether trait has type parameter bounds. + bool has_type_param_bounds () const { return !type_param_bounds.empty (); } + + // Returns whether trait has where clause. + bool has_where_clause () const { return !where_clause.is_empty (); } + + // Returns whether trait has trait items. + bool has_trait_items () const { return !trait_items.empty (); } + + // Returns whether trait has inner attributes. + bool has_inner_attrs () const { return !inner_attrs.empty (); } + + Identifier get_identifier () const { return name; } + + bool is_unsafe () const { return has_unsafe; } + + // Mega-constructor + Trait (Identifier name, bool is_unsafe, + std::vector> generic_params, + std::vector> type_param_bounds, + WhereClause where_clause, + std::vector> trait_items, Visibility vis, + std::vector outer_attrs, std::vector inner_attrs, + Location locus) + : VisItem (std::move (vis), std::move (outer_attrs)), + has_unsafe (is_unsafe), name (std::move (name)), + generic_params (std::move (generic_params)), + type_param_bounds (std::move (type_param_bounds)), + where_clause (std::move (where_clause)), + inner_attrs (std::move (inner_attrs)), + trait_items (std::move (trait_items)), locus (locus) + {} + + // Copy constructor with vector clone + Trait (Trait const &other) + : VisItem (other), has_unsafe (other.has_unsafe), name (other.name), + where_clause (other.where_clause), inner_attrs (other.inner_attrs), + locus (other.locus) + { + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + trait_items.reserve (other.trait_items.size ()); + for (const auto &e : other.trait_items) + trait_items.push_back (e->clone_trait_item ()); + } + + // Overloaded assignment operator with vector clone + Trait &operator= (Trait const &other) + { + VisItem::operator= (other); + name = other.name; + has_unsafe = other.has_unsafe; + where_clause = other.where_clause; + inner_attrs = other.inner_attrs; + locus = other.locus; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + trait_items.reserve (other.trait_items.size ()); + for (const auto &e : other.trait_items) + trait_items.push_back (e->clone_trait_item ()); + + return *this; + } + + // default move constructors + Trait (Trait &&other) = default; + Trait &operator= (Trait &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if trait name is empty, so base stripping on that. + void mark_for_strip () override { name = ""; } + bool is_marked_for_strip () const override { return name.empty (); } + + // TODO: think of better way to do this + const std::vector &get_inner_attrs () const { return inner_attrs; } + std::vector &get_inner_attrs () { return inner_attrs; } + + const std::vector> &get_trait_items () const + { + return trait_items; + } + std::vector> &get_trait_items () + { + return trait_items; + } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + std::vector> &get_type_param_bounds () + { + return type_param_bounds; + } + const std::vector> & + get_type_param_bounds () const + { + return type_param_bounds; + } + + WhereClause &get_where_clause () { return where_clause; } + + void insert_implict_self (std::unique_ptr &¶m) + { + std::vector> new_list; + new_list.reserve (generic_params.size () + 1); + + new_list.push_back (std::move (param)); + for (auto &p : generic_params) + { + new_list.push_back (std::move (p)); + } + + generic_params = std::move (new_list); + } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + Trait *clone_item_impl () const override { return new Trait (*this); } +}; + +// Implementation item declaration AST node - abstract base class +class Impl : public VisItem +{ + // must be protected to allow subclasses to access them properly +protected: + // bool has_generics; + // Generics generic_params; + std::vector> generic_params; // inlined + + std::unique_ptr trait_type; + + // bool has_where_clause; + WhereClause where_clause; + + // bool has_inner_attrs; + std::vector inner_attrs; + +private: + // doesn't really need to be protected as write access probably not needed + Location locus; + +public: + // Returns whether impl has generic parameters. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether impl has where clause. + bool has_where_clause () const { return !where_clause.is_empty (); } + + // Returns whether impl has inner attributes. + bool has_inner_attrs () const { return !inner_attrs.empty (); } + + Location get_locus () const override final { return locus; } + + // Invalid if trait type is null, so base stripping on that. + void mark_for_strip () override { trait_type = nullptr; } + bool is_marked_for_strip () const override { return trait_type == nullptr; } + + // TODO: think of better way to do this + const std::vector &get_inner_attrs () const { return inner_attrs; } + std::vector &get_inner_attrs () { return inner_attrs; } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () { return where_clause; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type () + { + rust_assert (trait_type != nullptr); + return trait_type; + } + +protected: + // Mega-constructor + Impl (std::vector> generic_params, + std::unique_ptr trait_type, WhereClause where_clause, + Visibility vis, std::vector inner_attrs, + std::vector outer_attrs, Location locus) + : VisItem (std::move (vis), std::move (outer_attrs)), + generic_params (std::move (generic_params)), + trait_type (std::move (trait_type)), + where_clause (std::move (where_clause)), + inner_attrs (std::move (inner_attrs)), locus (locus) + {} + + // Copy constructor + Impl (Impl const &other) + : VisItem (other), where_clause (other.where_clause), + inner_attrs (other.inner_attrs), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.trait_type != nullptr) + trait_type = other.trait_type->clone_type (); + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + } + + // Assignment operator overload with cloning + Impl &operator= (Impl const &other) + { + VisItem::operator= (other); + where_clause = other.where_clause; + inner_attrs = other.inner_attrs; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.trait_type != nullptr) + trait_type = other.trait_type->clone_type (); + else + trait_type = nullptr; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; + } + + // move constructors + Impl (Impl &&other) = default; + Impl &operator= (Impl &&other) = default; +}; + +// Regular "impl foo" impl block declaration AST node +class InherentImpl : public Impl +{ + // bool has_impl_items; + std::vector> impl_items; + +public: + std::string as_string () const override; + + // Returns whether inherent impl block has inherent impl items. + bool has_impl_items () const { return !impl_items.empty (); } + + // Mega-constructor + InherentImpl (std::vector> impl_items, + std::vector> generic_params, + std::unique_ptr trait_type, WhereClause where_clause, + Visibility vis, std::vector inner_attrs, + std::vector outer_attrs, Location locus) + : Impl (std::move (generic_params), std::move (trait_type), + std::move (where_clause), std::move (vis), std::move (inner_attrs), + std::move (outer_attrs), locus), + impl_items (std::move (impl_items)) + {} + + // Copy constructor with vector clone + InherentImpl (InherentImpl const &other) : Impl (other) + { + impl_items.reserve (other.impl_items.size ()); + for (const auto &e : other.impl_items) + impl_items.push_back (e->clone_inherent_impl_item ()); + } + + // Overloaded assignment operator with vector clone + InherentImpl &operator= (InherentImpl const &other) + { + Impl::operator= (other); + + impl_items.reserve (other.impl_items.size ()); + for (const auto &e : other.impl_items) + impl_items.push_back (e->clone_inherent_impl_item ()); + + return *this; + } + + // default move constructors + InherentImpl (InherentImpl &&other) = default; + InherentImpl &operator= (InherentImpl &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: think of better way to do this + const std::vector> &get_impl_items () const + { + return impl_items; + } + std::vector> &get_impl_items () + { + return impl_items; + } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + InherentImpl *clone_item_impl () const override + { + return new InherentImpl (*this); + } +}; + +// The "impl footrait for foo" impl block declaration AST node +class TraitImpl : public Impl +{ + bool has_unsafe; + bool has_exclam; + TypePath trait_path; + + // bool has_impl_items; + std::vector> impl_items; + +public: + std::string as_string () const override; + + // Returns whether trait impl has impl items. + bool has_impl_items () const { return !impl_items.empty (); } + + // Mega-constructor + TraitImpl (TypePath trait_path, bool is_unsafe, bool has_exclam, + std::vector> impl_items, + std::vector> generic_params, + std::unique_ptr trait_type, WhereClause where_clause, + Visibility vis, std::vector inner_attrs, + std::vector outer_attrs, Location locus) + : Impl (std::move (generic_params), std::move (trait_type), + std::move (where_clause), std::move (vis), std::move (inner_attrs), + std::move (outer_attrs), locus), + has_unsafe (is_unsafe), has_exclam (has_exclam), + trait_path (std::move (trait_path)), impl_items (std::move (impl_items)) + {} + + // Copy constructor with vector clone + TraitImpl (TraitImpl const &other) + : Impl (other), has_unsafe (other.has_unsafe), + has_exclam (other.has_exclam), trait_path (other.trait_path) + { + impl_items.reserve (other.impl_items.size ()); + for (const auto &e : other.impl_items) + impl_items.push_back (e->clone_trait_impl_item ()); + } + + // Overloaded assignment operator with vector clone + TraitImpl &operator= (TraitImpl const &other) + { + Impl::operator= (other); + trait_path = other.trait_path; + has_unsafe = other.has_unsafe; + has_exclam = other.has_exclam; + + impl_items.reserve (other.impl_items.size ()); + for (const auto &e : other.impl_items) + impl_items.push_back (e->clone_trait_impl_item ()); + + return *this; + } + + // move constructors + TraitImpl (TraitImpl &&other) = default; + TraitImpl &operator= (TraitImpl &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + bool is_unsafe () const { return has_unsafe; }; + bool is_exclam () const { return has_exclam; } + + // TODO: think of better way to do this + const std::vector> &get_impl_items () const + { + return impl_items; + } + std::vector> &get_impl_items () + { + return impl_items; + } + + // TODO: is this better? Or is a "vis_block" better? + TypePath &get_trait_path () + { + // TODO: assert that trait path is not empty? + return trait_path; + } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + TraitImpl *clone_item_impl () const override { return new TraitImpl (*this); } +}; + +#if 0 +// Abstract base class for an item used inside an extern block +class ExternalItem +{ + // bool has_outer_attrs; + std::vector outer_attrs; + + // bool has_visibility; + Visibility visibility; + + Identifier item_name; + Location locus; + +public: + virtual ~ExternalItem () {} + + /* TODO: spec syntax rules state that "MacroInvocationSemi" can be used as + * ExternalItem, but text body isn't so clear. Adding MacroInvocationSemi + * support would require a lot of refactoring. */ + + // Returns whether item has outer attributes. + bool has_outer_attrs () const { return !outer_attrs.empty (); } + + // Returns whether item has non-default visibility. + bool has_visibility () const { return !visibility.is_error (); } + + // Unique pointer custom clone function + std::unique_ptr clone_external_item () const + { + return std::unique_ptr (clone_external_item_impl ()); + } + + virtual std::string as_string () const; + + Location get_locus () const override final { return locus; } + + virtual void accept_vis (ASTVisitor &vis) = 0; + + // TODO: make virtual? Would be more flexible. + // Based on idea that name should never be empty. + void mark_for_strip () { item_name = ""; }; + bool is_marked_for_strip () const { return item_name.empty (); }; + +protected: + ExternalItem (Identifier item_name, Visibility vis, + std::vector outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)), + item_name (std::move (item_name)), locus (locus) + {} + + // Copy constructor + ExternalItem (ExternalItem const &other) + : outer_attrs (other.outer_attrs), visibility (other.visibility), + item_name (other.item_name), locus (other.locus) + {} + + // Overloaded assignment operator to clone + ExternalItem &operator= (ExternalItem const &other) + { + item_name = other.item_name; + visibility = other.visibility; + outer_attrs = other.outer_attrs; + locus = other.locus; + + return *this; + } + + // move constructors + ExternalItem (ExternalItem &&other) = default; + ExternalItem &operator= (ExternalItem &&other) = default; + + // Clone function implementation as pure virtual method + virtual ExternalItem *clone_external_item_impl () const = 0; + + // possibly make this public if required + std::string get_item_name () const { return item_name; } +}; +#endif + +// A static item used in an extern block +class ExternalStaticItem : public ExternalItem +{ + // bool has_outer_attrs; + std::vector outer_attrs; + + // bool has_visibility; + Visibility visibility; + + Identifier item_name; + Location locus; + + bool has_mut; + std::unique_ptr item_type; + +public: + ExternalStaticItem (Identifier item_name, std::unique_ptr item_type, + bool is_mut, Visibility vis, + std::vector outer_attrs, Location locus) + : ExternalItem (), outer_attrs (std::move (outer_attrs)), + visibility (std::move (vis)), item_name (std::move (item_name)), + locus (locus), has_mut (is_mut), item_type (std::move (item_type)) + {} + + // Copy constructor + ExternalStaticItem (ExternalStaticItem const &other) + : outer_attrs (other.outer_attrs), visibility (other.visibility), + item_name (other.item_name), locus (other.locus), has_mut (other.has_mut) + { + node_id = other.node_id; + // guard to prevent null dereference (only required if error state) + if (other.item_type != nullptr) + item_type = other.item_type->clone_type (); + } + + // Overloaded assignment operator to clone + ExternalStaticItem &operator= (ExternalStaticItem const &other) + { + node_id = other.node_id; + outer_attrs = other.outer_attrs; + visibility = other.visibility; + item_name = other.item_name; + locus = other.locus; + has_mut = other.has_mut; + + // guard to prevent null dereference (only required if error state) + if (other.item_type != nullptr) + item_type = other.item_type->clone_type (); + else + item_type = nullptr; + + return *this; + } + + // move constructors + ExternalStaticItem (ExternalStaticItem &&other) = default; + ExternalStaticItem &operator= (ExternalStaticItem &&other) = default; + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + // Returns whether item has outer attributes. + bool has_outer_attrs () const { return !outer_attrs.empty (); } + + // Returns whether item has non-default visibility. + bool has_visibility () const { return !visibility.is_error (); } + + Location get_locus () const { return locus; } + + // Based on idea that type should never be null. + void mark_for_strip () override { item_type = nullptr; }; + bool is_marked_for_strip () const override { return item_type == nullptr; }; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type () + { + rust_assert (item_type != nullptr); + return item_type; + } + + Identifier get_identifier () const { return item_name; } + + const Visibility &get_visibility () const { return visibility; } + + bool is_mut () const { return has_mut; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + ExternalStaticItem *clone_external_item_impl () const override + { + return new ExternalStaticItem (*this); + } +}; + +// A named function parameter used in external functions +struct NamedFunctionParam +{ +private: + // bool has_name; // otherwise is _ + std::string name; + + std::unique_ptr param_type; + + // seemingly new since writing this node + std::vector outer_attrs; + + NodeId node_id; + Location locus; + +public: + /* Returns whether the named function parameter has a name (i.e. name is not + * '_'). */ + bool has_name () const { return name != "_"; } + + bool has_outer_attrs () const { return !outer_attrs.empty (); } + + // Returns whether the named function parameter is in an error state. + bool is_error () const + { + // also if identifier is "" but that is probably more costly to compute + return param_type == nullptr; + } + + std::string get_name () const { return name; } + + // Creates an error state named function parameter. + static NamedFunctionParam create_error () + { + return NamedFunctionParam ("", nullptr, {}, Location ()); + } + + NamedFunctionParam (std::string name, std::unique_ptr param_type, + std::vector outer_attrs, Location locus) + : name (std::move (name)), param_type (std::move (param_type)), + outer_attrs (std::move (outer_attrs)), + node_id (Analysis::Mappings::get ()->get_next_node_id ()), locus (locus) + {} + + // Copy constructor + NamedFunctionParam (NamedFunctionParam const &other) + : name (other.name), outer_attrs (other.outer_attrs) + { + node_id = other.node_id; + // guard to prevent null dereference (only required if error state) + if (other.param_type != nullptr) + param_type = other.param_type->clone_type (); + } + + ~NamedFunctionParam () = default; + + // Overloaded assignment operator to clone + NamedFunctionParam &operator= (NamedFunctionParam const &other) + { + node_id = other.node_id; + name = other.name; + // has_name = other.has_name; + outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.param_type != nullptr) + param_type = other.param_type->clone_type (); + else + param_type = nullptr; + + return *this; + } + + // move constructors + NamedFunctionParam (NamedFunctionParam &&other) = default; + NamedFunctionParam &operator= (NamedFunctionParam &&other) = default; + + std::string as_string () const; + + // Based on idea that nane should never be empty. + void mark_for_strip () { param_type = nullptr; }; + bool is_marked_for_strip () const { return is_error (); }; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type () + { + rust_assert (param_type != nullptr); + return param_type; + } + + NodeId get_node_id () const { return node_id; } +}; + +// A function item used in an extern block +class ExternalFunctionItem : public ExternalItem +{ + // bool has_outer_attrs; + std::vector outer_attrs; + + // bool has_visibility; + Visibility visibility; + + Identifier item_name; + Location locus; + + // bool has_generics; + // Generics generic_params; + std::vector> generic_params; // inlined + + // bool has_return_type; + // FunctionReturnType return_type; + std::unique_ptr return_type; // inlined + + // bool has_where_clause; + WhereClause where_clause; + + std::vector function_params; + bool has_variadics; + std::vector variadic_outer_attrs; + +public: + // Returns whether item has generic parameters. + bool has_generics () const { return !generic_params.empty (); } + + // Returns whether item has a return type (otherwise void). + bool has_return_type () const { return return_type != nullptr; } + + // Returns whether item has a where clause. + bool has_where_clause () const { return !where_clause.is_empty (); } + + // Returns whether item has outer attributes. + bool has_outer_attrs () const { return !outer_attrs.empty (); } + + // Returns whether item has non-default visibility. + bool has_visibility () const { return !visibility.is_error (); } + + // Returns whether item has variadic parameters. + bool is_variadic () const { return has_variadics; } + + // Returns whether item has outer attributes on its variadic parameters. + bool has_variadic_outer_attrs () const + { + return !variadic_outer_attrs.empty (); + } + + Location get_locus () const { return locus; } + + const Visibility &get_visibility () const { return visibility; } + + ExternalFunctionItem ( + Identifier item_name, + std::vector> generic_params, + std::unique_ptr return_type, WhereClause where_clause, + std::vector function_params, bool has_variadics, + std::vector variadic_outer_attrs, Visibility vis, + std::vector outer_attrs, Location locus) + : ExternalItem (), outer_attrs (std::move (outer_attrs)), + visibility (std::move (vis)), item_name (std::move (item_name)), + locus (locus), generic_params (std::move (generic_params)), + return_type (std::move (return_type)), + where_clause (std::move (where_clause)), + function_params (std::move (function_params)), + has_variadics (has_variadics), + variadic_outer_attrs (std::move (variadic_outer_attrs)) + { + // TODO: assert that if has variadic outer attrs, then has_variadics is + // true? + } + + // Copy constructor with clone + ExternalFunctionItem (ExternalFunctionItem const &other) + : outer_attrs (other.outer_attrs), visibility (other.visibility), + item_name (other.item_name), locus (other.locus), + where_clause (other.where_clause), + function_params (other.function_params), + has_variadics (other.has_variadics), + variadic_outer_attrs (other.variadic_outer_attrs) + { + node_id = other.node_id; + // guard to prevent null pointer dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + } + + // Overloaded assignment operator with clone + ExternalFunctionItem &operator= (ExternalFunctionItem const &other) + { + outer_attrs = other.outer_attrs; + visibility = other.visibility; + item_name = other.item_name; + locus = other.locus; + where_clause = other.where_clause; + function_params = other.function_params; + has_variadics = other.has_variadics; + variadic_outer_attrs = other.variadic_outer_attrs; + node_id = other.node_id; + + // guard to prevent null pointer dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; + } + + // move constructors + ExternalFunctionItem (ExternalFunctionItem &&other) = default; + ExternalFunctionItem &operator= (ExternalFunctionItem &&other) = default; + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + // Based on idea that nane should never be empty. + void mark_for_strip () override { item_name = ""; }; + bool is_marked_for_strip () const override { return item_name.empty (); }; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector &get_outer_attrs () { return outer_attrs; } + const std::vector &get_outer_attrs () const { return outer_attrs; } + + std::vector &get_function_params () + { + return function_params; + } + const std::vector &get_function_params () const + { + return function_params; + } + + std::vector> &get_generic_params () + { + return generic_params; + } + const std::vector> &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () { return where_clause; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; + } + + Identifier get_identifier () const { return item_name; }; + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + ExternalFunctionItem *clone_external_item_impl () const override + { + return new ExternalFunctionItem (*this); + } +}; + +// An extern block AST node +class ExternBlock : public VisItem +{ + // bool has_abi; + std::string abi; + + // bool has_inner_attrs; + std::vector inner_attrs; + + // bool has_extern_items; + std::vector> extern_items; + + Location locus; + + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + +public: + std::string as_string () const override; + + // Returns whether extern block has inner attributes. + bool has_inner_attrs () const { return !inner_attrs.empty (); } + + // Returns whether extern block has extern items. + bool has_extern_items () const { return !extern_items.empty (); } + + // Returns whether extern block has ABI name. + bool has_abi () const { return !abi.empty (); } + + std::string get_abi () const { return abi; } + + ExternBlock (std::string abi, + std::vector> extern_items, + Visibility vis, std::vector inner_attrs, + std::vector outer_attrs, Location locus) + : VisItem (std::move (vis), std::move (outer_attrs)), abi (std::move (abi)), + inner_attrs (std::move (inner_attrs)), + extern_items (std::move (extern_items)), locus (locus) + {} + + // Copy constructor with vector clone + ExternBlock (ExternBlock const &other) + : VisItem (other), abi (other.abi), inner_attrs (other.inner_attrs), + locus (other.locus), marked_for_strip (other.marked_for_strip) + { + extern_items.reserve (other.extern_items.size ()); + for (const auto &e : other.extern_items) + extern_items.push_back (e->clone_external_item ()); + } + + // Overloaded assignment operator with vector clone + ExternBlock &operator= (ExternBlock const &other) + { + VisItem::operator= (other); + abi = other.abi; + inner_attrs = other.inner_attrs; + locus = other.locus; + marked_for_strip = other.marked_for_strip; + + extern_items.reserve (other.extern_items.size ()); + for (const auto &e : other.extern_items) + extern_items.push_back (e->clone_external_item ()); + + return *this; + } + + // move constructors + ExternBlock (ExternBlock &&other) = default; + ExternBlock &operator= (ExternBlock &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + // TODO: think of better way to do this + const std::vector> &get_extern_items () const + { + return extern_items; + } + std::vector> &get_extern_items () + { + return extern_items; + } + + // TODO: think of better way to do this + const std::vector &get_inner_attrs () const { return inner_attrs; } + std::vector &get_inner_attrs () { return inner_attrs; } + +protected: + /* Use covariance to implement clone function as returning this object + * rather than base */ + ExternBlock *clone_item_impl () const override + { + return new ExternBlock (*this); + } +}; + +// Replaced with forward decls - defined in "rust-macro.h" +class MacroItem; +class MacroRulesDefinition; +} // namespace AST +} // namespace Rust + +#endif From patchwork Tue Dec 6 10:13:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61505 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6230C396E473 for ; Tue, 6 Dec 2022 10:15:26 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by sourceware.org (Postfix) with ESMTPS id 66129396DC20 for ; Tue, 6 Dec 2022 10:12:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 66129396DC20 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x42b.google.com with SMTP id h11so22681735wrw.13 for ; Tue, 06 Dec 2022 02:12:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=hy+TJUB6I08rBgm7JO6+hCS6dOk0nBj9JL9ssw6sIC4=; b=WY6ai7F3P2qNV2DXLQv6nbbZ2VdhEZr6kq1FRU4Co/EFpbN6Q1z7E3QzSqGwlEyl9o 5M5inVOJDNqgONyEbtjwsG3fY7RDU9Xo4X8IOIJIDPkJNlBxNtADus17wT2Lf8jOwlLj PDjxnMGgHSWfd5EH72SdJqrmluClagsz7QQnzncoMRXNlPeK08P00xtOsH13pTOmPWxb nIT+12O1+wMYOC9KN/LEqmbVjdHT2AY8oQ1G3uwLRkb5lGegtsZE2piwQlO9WTNDYFYj 2BIZj1BziX96Eg3S81nEGpkPyv1NwR3VoEl8s/pyJAp8z1cKLMRKGiwdKabrGCJggNzj gr+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=hy+TJUB6I08rBgm7JO6+hCS6dOk0nBj9JL9ssw6sIC4=; b=bcA/xCjNav/jhYm+0BtfSYgYRhUuxOYD8ar/3eA7FFL6/pBpeCHh0QqfPF3TPGsNRz hIQRyb3WOkKWUh3MykRoTnoXOxDblWFl1JxrlbNDSMS0tUXthYkB/tepBgBbAhvIdDe+ vzZMifcRdBbGdaj/24Kf5E3D+TTmNudb+qget3AHQZZHO8qF2mb6VwcMHEf6hVH9K+x3 0EB8d+bMZlv8hPuDEEhd5biUS07ydrHRo7P0I/jAot/R1RVRisVUszc1bzCLGjec6FcH /gnMK0PNBucj2INgdOULg8o2Kdt0Bd/NYPRmbvbLv86VWZE6paZY8arpzhcc7/I8u7Hs dM+g== X-Gm-Message-State: ANoB5pkjIzpgKzxBYP3Ae38On0zJr+/6KS4odAh72Co8dMiYobrjcPg3 W0113s6h59gYkKs8xJc0hLWlytAYaJ2hpi7jMw== X-Google-Smtp-Source: AA0mqf6X3VQ7+b82qtW7Y/iflgqXE9QwRbmRkFSUi5CQBqcLhwif0QhbFNZy5tnE8/GiZ6zEbVVz2g== X-Received: by 2002:adf:dec5:0:b0:242:3421:e11 with SMTP id i5-20020adfdec5000000b0024234210e11mr13708388wrn.245.1670321521994; Tue, 06 Dec 2022 02:12:01 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.12.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:12:01 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, The Other , Philip Herron Subject: [PATCH Rust front-end v4 10/46] gccrs: Add full definitions of Rust AST data structures Date: Tue, 6 Dec 2022 11:13:42 +0100 Message-Id: <20221206101417.778807-11-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-18.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: The Other This adds the proper definitions of our AST nodes split across multiple files for clarity Co-authored-by: Philip Herron --- gcc/rust/ast/rust-expr.h | 4631 +++++++++++++++++++++++++++++++++++ gcc/rust/ast/rust-macro.h | 958 ++++++++ gcc/rust/ast/rust-path.h | 1297 ++++++++++ gcc/rust/ast/rust-pattern.h | 1576 ++++++++++++ gcc/rust/ast/rust-stmt.h | 358 +++ gcc/rust/ast/rust-type.h | 962 ++++++++ 6 files changed, 9782 insertions(+) create mode 100644 gcc/rust/ast/rust-expr.h create mode 100644 gcc/rust/ast/rust-macro.h create mode 100644 gcc/rust/ast/rust-path.h create mode 100644 gcc/rust/ast/rust-pattern.h create mode 100644 gcc/rust/ast/rust-stmt.h create mode 100644 gcc/rust/ast/rust-type.h diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h new file mode 100644 index 00000000000..1966a590c94 --- /dev/null +++ b/gcc/rust/ast/rust-expr.h @@ -0,0 +1,4631 @@ +#ifndef RUST_AST_EXPR_H +#define RUST_AST_EXPR_H + +#include "rust-ast.h" +#include "rust-path.h" +#include "operator.h" + +namespace Rust { +namespace AST { +/* TODO: if GCC moves to C++17 or allows boost, replace some boolean + * "has_whatever" pairs with + * optional types (std::optional or boost::optional)? */ + +// AST node for an expression with an accompanying block - abstract +class ExprWithBlock : public Expr +{ +protected: + // pure virtual clone implementation + virtual ExprWithBlock *clone_expr_with_block_impl () const = 0; + + // prevent having to define multiple clone expressions + ExprWithBlock *clone_expr_impl () const final override + { + return clone_expr_with_block_impl (); + } + + bool is_expr_without_block () const final override { return false; }; + +public: + // Unique pointer custom clone function + std::unique_ptr clone_expr_with_block () const + { + return std::unique_ptr (clone_expr_with_block_impl ()); + } +}; + +// Literals? Or literal base? +class LiteralExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + Literal literal; + Location locus; + +public: + std::string as_string () const override { return literal.as_string (); } + + Literal::LitType get_lit_type () const { return literal.get_lit_type (); } + + LiteralExpr (std::string value_as_string, Literal::LitType type, + PrimitiveCoreType type_hint, std::vector outer_attrs, + Location locus) + : outer_attrs (std::move (outer_attrs)), + literal (std::move (value_as_string), type, type_hint), locus (locus) + {} + + LiteralExpr (Literal literal, std::vector outer_attrs, + Location locus) + : outer_attrs (std::move (outer_attrs)), literal (std::move (literal)), + locus (locus) + {} + + // Unique pointer custom clone function + std::unique_ptr clone_literal_expr () const + { + return std::unique_ptr (clone_literal_expr_impl ()); + } + + Location get_locus () const override final { return locus; } + + Literal get_literal () const { return literal; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if literal is in error state, so base stripping on that. + void mark_for_strip () override { literal = Literal::create_error (); } + bool is_marked_for_strip () const override { return literal.is_error (); } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + LiteralExpr *clone_expr_without_block_impl () const final override + { + return clone_literal_expr_impl (); + } + + /* not virtual as currently no subclasses of LiteralExpr, but could be in + * future */ + /*virtual*/ LiteralExpr *clone_literal_expr_impl () const + { + return new LiteralExpr (*this); + } +}; + +// Literal expression attribute body (non-macro attribute) +class AttrInputLiteral : public AttrInput +{ + LiteralExpr literal_expr; + +public: + AttrInputLiteral (LiteralExpr lit_expr) : literal_expr (std::move (lit_expr)) + {} + + std::string as_string () const override + { + return " = " + literal_expr.as_string (); + } + + void accept_vis (ASTVisitor &vis) override; + + /* this can never be a cfg predicate - cfg and cfg_attr require a token-tree + * cfg */ + bool check_cfg_predicate (const Session &) const override { return false; } + + bool is_meta_item () const override { return false; } + + LiteralExpr &get_literal () { return literal_expr; } + + AttrInputType get_attr_input_type () const final override + { + return AttrInput::AttrInputType::LITERAL; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + AttrInputLiteral *clone_attr_input_impl () const override + { + return new AttrInputLiteral (*this); + } +}; + +/* literal expr only meta item inner - TODO possibly replace with inheritance of + * LiteralExpr itself? */ +class MetaItemLitExpr : public MetaItemInner +{ + LiteralExpr lit_expr; + +public: + MetaItemLitExpr (LiteralExpr lit_expr) : lit_expr (std::move (lit_expr)) {} + + std::string as_string () const override { return lit_expr.as_string (); } + + void accept_vis (ASTVisitor &vis) override; + + bool check_cfg_predicate (const Session &session) const override; + +protected: + // Use covariance to implement clone function as returning this type + MetaItemLitExpr *clone_meta_item_inner_impl () const override + { + return new MetaItemLitExpr (*this); + } +}; + +// more generic meta item "path = lit" form +class MetaItemPathLit : public MetaItem +{ + SimplePath path; + LiteralExpr lit; + +public: + MetaItemPathLit (SimplePath path, LiteralExpr lit_expr) + : path (std::move (path)), lit (std::move (lit_expr)) + {} + + std::string as_string () const override + { + return path.as_string () + " = " + lit.as_string (); + } + + void accept_vis (ASTVisitor &vis) override; + + bool check_cfg_predicate (const Session &session) const override; + /* TODO: return true if "ident" is defined and value of it is "lit", return + * false otherwise */ + + Attribute to_attribute () const override; + +protected: + // Use covariance to implement clone function as returning this type + MetaItemPathLit *clone_meta_item_inner_impl () const override + { + return new MetaItemPathLit (*this); + } +}; + +/* Represents an expression using unary or binary operators as AST node. Can be + * overloaded. */ +class OperatorExpr : public ExprWithoutBlock +{ + // TODO: create binary and unary operator subclasses? +public: + Location locus; + +protected: + /* Variables must be protected to allow derived classes to use them as first + * class citizens */ + std::vector outer_attrs; + std::unique_ptr main_or_left_expr; + + // Constructor (only for initialisation of expr purposes) + OperatorExpr (std::unique_ptr main_or_left_expr, + std::vector outer_attribs, Location locus) + : locus (locus), outer_attrs (std::move (outer_attribs)), + main_or_left_expr (std::move (main_or_left_expr)) + {} + + // Copy constructor (only for initialisation of expr purposes) + OperatorExpr (OperatorExpr const &other) + : locus (other.locus), outer_attrs (other.outer_attrs) + { + // guard to prevent null dereference (only required if error state) + if (other.main_or_left_expr != nullptr) + main_or_left_expr = other.main_or_left_expr->clone_expr (); + } + + // Overload assignment operator to deep copy expr + OperatorExpr &operator= (OperatorExpr const &other) + { + ExprWithoutBlock::operator= (other); + locus = other.locus; + outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.main_or_left_expr != nullptr) + main_or_left_expr = other.main_or_left_expr->clone_expr (); + else + main_or_left_expr = nullptr; + + return *this; + } + + // move constructors + OperatorExpr (OperatorExpr &&other) = default; + OperatorExpr &operator= (OperatorExpr &&other) = default; + +public: + Location get_locus () const override final { return locus; } + + // Invalid if expr is null, so base stripping on that. + void mark_for_strip () override { main_or_left_expr = nullptr; } + bool is_marked_for_strip () const override + { + return main_or_left_expr == nullptr; + } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } +}; + +/* Unary prefix & or &mut (or && and &&mut) borrow operator. Cannot be + * overloaded. */ +class BorrowExpr : public OperatorExpr +{ + bool is_mut; + bool double_borrow; + +public: + std::string as_string () const override; + + BorrowExpr (std::unique_ptr borrow_lvalue, bool is_mut_borrow, + bool is_double_borrow, std::vector outer_attribs, + Location locus) + : OperatorExpr (std::move (borrow_lvalue), std::move (outer_attribs), + locus), + is_mut (is_mut_borrow), double_borrow (is_double_borrow) + {} + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_borrowed_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + + bool get_is_mut () const { return is_mut; } + + bool get_is_double_borrow () const { return double_borrow; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + BorrowExpr *clone_expr_without_block_impl () const override + { + return new BorrowExpr (*this); + } +}; + +// Unary prefix * deference operator +class DereferenceExpr : public OperatorExpr +{ +public: + std::string as_string () const override; + + // Constructor calls OperatorExpr's protected constructor + DereferenceExpr (std::unique_ptr deref_lvalue, + std::vector outer_attribs, Location locus) + : OperatorExpr (std::move (deref_lvalue), std::move (outer_attribs), locus) + {} + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_dereferenced_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + DereferenceExpr *clone_expr_without_block_impl () const override + { + return new DereferenceExpr (*this); + } +}; + +// Unary postfix ? error propogation operator. Cannot be overloaded. +class ErrorPropagationExpr : public OperatorExpr +{ +public: + std::string as_string () const override; + + // Constructor calls OperatorExpr's protected constructor + ErrorPropagationExpr (std::unique_ptr potential_error_value, + std::vector outer_attribs, Location locus) + : OperatorExpr (std::move (potential_error_value), + std::move (outer_attribs), locus) + {} + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_propagating_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ErrorPropagationExpr *clone_expr_without_block_impl () const override + { + return new ErrorPropagationExpr (*this); + } +}; + +// Unary prefix - or ! negation or NOT operators. +class NegationExpr : public OperatorExpr +{ +public: + using ExprType = NegationOperator; + +private: + /* Note: overload negation via std::ops::Neg and not via std::ops::Not + * Negation only works for signed integer and floating-point types, NOT only + * works for boolean and integer types (via bitwise NOT) */ + ExprType expr_type; + +public: + std::string as_string () const override; + + ExprType get_expr_type () const { return expr_type; } + + // Constructor calls OperatorExpr's protected constructor + NegationExpr (std::unique_ptr negated_value, ExprType expr_kind, + std::vector outer_attribs, Location locus) + : OperatorExpr (std::move (negated_value), std::move (outer_attribs), + locus), + expr_type (expr_kind) + {} + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_negated_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + NegationExpr *clone_expr_without_block_impl () const override + { + return new NegationExpr (*this); + } +}; + +// Infix binary operators. +, -, *, /, %, &, |, ^, <<, >> +class ArithmeticOrLogicalExpr : public OperatorExpr +{ +public: + using ExprType = ArithmeticOrLogicalOperator; + +private: + // Note: overloading trait specified in comments + ExprType expr_type; + + std::unique_ptr right_expr; + +public: + std::string as_string () const override; + + ExprType get_expr_type () const { return expr_type; } + + // Constructor calls OperatorExpr's protected constructor + ArithmeticOrLogicalExpr (std::unique_ptr left_value, + std::unique_ptr right_value, + ExprType expr_kind, Location locus) + : OperatorExpr (std::move (left_value), std::vector (), locus), + expr_type (expr_kind), right_expr (std::move (right_value)) + {} + // outer attributes not allowed + + // Copy constructor - probably required due to unique pointer + ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr const &other) + : OperatorExpr (other), expr_type (other.expr_type), + right_expr (other.right_expr->clone_expr ()) + {} + + // Overload assignment operator + ArithmeticOrLogicalExpr &operator= (ArithmeticOrLogicalExpr const &other) + { + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + expr_type = other.expr_type; + + return *this; + } + + // move constructors + ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr &&other) = default; + ArithmeticOrLogicalExpr &operator= (ArithmeticOrLogicalExpr &&other) + = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_left_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_right_expr () + { + rust_assert (right_expr != nullptr); + return right_expr; + } + + void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); } + void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ArithmeticOrLogicalExpr *clone_expr_without_block_impl () const override + { + return new ArithmeticOrLogicalExpr (*this); + } +}; + +// Infix binary comparison operators. ==, !=, <, <=, >, >= +class ComparisonExpr : public OperatorExpr +{ +public: + using ExprType = ComparisonOperator; + +private: + // Note: overloading trait specified in comments + ExprType expr_type; + + std::unique_ptr right_expr; + +public: + std::string as_string () const override; + + ExprType get_expr_type () const { return expr_type; } + + // Constructor requires pointers for polymorphism + ComparisonExpr (std::unique_ptr left_value, + std::unique_ptr right_value, ExprType comparison_kind, + Location locus) + : OperatorExpr (std::move (left_value), std::vector (), locus), + expr_type (comparison_kind), right_expr (std::move (right_value)) + {} + // outer attributes not allowed + + // Copy constructor also calls OperatorExpr's protected constructor + ComparisonExpr (ComparisonExpr const &other) + : OperatorExpr (other), expr_type (other.expr_type), + right_expr (other.right_expr->clone_expr ()) + {} + + // Overload assignment operator to deep copy + ComparisonExpr &operator= (ComparisonExpr const &other) + { + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + expr_type = other.expr_type; + // outer_attrs = other.outer_attrs; + + return *this; + } + + // move constructors + ComparisonExpr (ComparisonExpr &&other) = default; + ComparisonExpr &operator= (ComparisonExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_left_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_right_expr () + { + rust_assert (right_expr != nullptr); + return right_expr; + } + + ExprType get_kind () { return expr_type; } + + /* TODO: implement via a function call to std::cmp::PartialEq::eq(&op1, &op2) + * maybe? */ +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ComparisonExpr *clone_expr_without_block_impl () const override + { + return new ComparisonExpr (*this); + } +}; + +// Infix binary lazy boolean logical operators && and ||. +class LazyBooleanExpr : public OperatorExpr +{ +public: + using ExprType = LazyBooleanOperator; + +private: + ExprType expr_type; + + std::unique_ptr right_expr; + +public: + // Constructor calls OperatorExpr's protected constructor + LazyBooleanExpr (std::unique_ptr left_bool_expr, + std::unique_ptr right_bool_expr, ExprType expr_kind, + Location locus) + : OperatorExpr (std::move (left_bool_expr), std::vector (), + locus), + expr_type (expr_kind), right_expr (std::move (right_bool_expr)) + {} + // outer attributes not allowed + + // Copy constructor also calls OperatorExpr's protected constructor + LazyBooleanExpr (LazyBooleanExpr const &other) + : OperatorExpr (other), expr_type (other.expr_type), + right_expr (other.right_expr->clone_expr ()) + {} + + // Overload assignment operator to deep copy + LazyBooleanExpr &operator= (LazyBooleanExpr const &other) + { + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + expr_type = other.expr_type; + + return *this; + } + + // move constructors + LazyBooleanExpr (LazyBooleanExpr &&other) = default; + LazyBooleanExpr &operator= (LazyBooleanExpr &&other) = default; + + std::string as_string () const override; + + ExprType get_expr_type () const { return expr_type; } + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_left_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_right_expr () + { + rust_assert (right_expr != nullptr); + return right_expr; + } + + ExprType get_kind () { return expr_type; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + LazyBooleanExpr *clone_expr_without_block_impl () const override + { + return new LazyBooleanExpr (*this); + } +}; + +// Binary infix "as" cast expression. +class TypeCastExpr : public OperatorExpr +{ + std::unique_ptr type_to_convert_to; + + // Note: only certain type casts allowed, outlined in reference +public: + std::string as_string () const override; + + // Constructor requires calling protected constructor of OperatorExpr + TypeCastExpr (std::unique_ptr expr_to_cast, + std::unique_ptr type_to_cast_to, Location locus) + : OperatorExpr (std::move (expr_to_cast), std::vector (), locus), + type_to_convert_to (std::move (type_to_cast_to)) + {} + // outer attributes not allowed + + // Copy constructor also requires calling protected constructor + TypeCastExpr (TypeCastExpr const &other) + : OperatorExpr (other), + type_to_convert_to (other.type_to_convert_to->clone_type_no_bounds ()) + {} + + // Overload assignment operator to deep copy + TypeCastExpr &operator= (TypeCastExpr const &other) + { + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + type_to_convert_to = other.type_to_convert_to->clone_type_no_bounds (); + + return *this; + } + + // move constructors + TypeCastExpr (TypeCastExpr &&other) = default; + TypeCastExpr &operator= (TypeCastExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_casted_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type_to_cast_to () + { + rust_assert (type_to_convert_to != nullptr); + return type_to_convert_to; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + TypeCastExpr *clone_expr_without_block_impl () const override + { + return new TypeCastExpr (*this); + } +}; + +// Binary assignment expression. +class AssignmentExpr : public OperatorExpr +{ + std::unique_ptr right_expr; + +public: + std::string as_string () const override; + + // Call OperatorExpr constructor to initialise left_expr + AssignmentExpr (std::unique_ptr value_to_assign_to, + std::unique_ptr value_to_assign, + std::vector outer_attribs, Location locus) + : OperatorExpr (std::move (value_to_assign_to), std::move (outer_attribs), + locus), + right_expr (std::move (value_to_assign)) + {} + // outer attributes not allowed + + // Call OperatorExpr constructor in copy constructor, as well as clone + AssignmentExpr (AssignmentExpr const &other) + : OperatorExpr (other), right_expr (other.right_expr->clone_expr ()) + {} + + // Overload assignment operator to clone unique_ptr right_expr + AssignmentExpr &operator= (AssignmentExpr const &other) + { + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + // outer_attrs = other.outer_attrs; + + return *this; + } + + // move constructors + AssignmentExpr (AssignmentExpr &&other) = default; + AssignmentExpr &operator= (AssignmentExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); } + void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_left_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_right_expr () + { + rust_assert (right_expr != nullptr); + return right_expr; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + AssignmentExpr *clone_expr_without_block_impl () const override + { + return new AssignmentExpr (*this); + } +}; + +/* Binary infix compound assignment (arithmetic or logic then assignment) + * expressions. */ +class CompoundAssignmentExpr : public OperatorExpr +{ +public: + using ExprType = CompoundAssignmentOperator; + +private: + // Note: overloading trait specified in comments + ExprType expr_type; + std::unique_ptr right_expr; + +public: + std::string as_string () const override; + + ExprType get_expr_type () const { return expr_type; } + + // Use pointers in constructor to enable polymorphism + CompoundAssignmentExpr (std::unique_ptr value_to_assign_to, + std::unique_ptr value_to_assign, + ExprType expr_kind, Location locus) + : OperatorExpr (std::move (value_to_assign_to), std::vector (), + locus), + expr_type (expr_kind), right_expr (std::move (value_to_assign)) + {} + // outer attributes not allowed + + // Have clone in copy constructor + CompoundAssignmentExpr (CompoundAssignmentExpr const &other) + : OperatorExpr (other), expr_type (other.expr_type), + right_expr (other.right_expr->clone_expr ()) + {} + + // Overload assignment operator to clone + CompoundAssignmentExpr &operator= (CompoundAssignmentExpr const &other) + { + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + expr_type = other.expr_type; + // outer_attrs = other.outer_attrs; + + return *this; + } + + // move constructors + CompoundAssignmentExpr (CompoundAssignmentExpr &&other) = default; + CompoundAssignmentExpr &operator= (CompoundAssignmentExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_left_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_right_expr () + { + rust_assert (right_expr != nullptr); + return right_expr; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + CompoundAssignmentExpr *clone_expr_without_block_impl () const override + { + return new CompoundAssignmentExpr (*this); + } +}; + +// Expression in parentheses (i.e. like literally just any 3 + (2 * 6)) +class GroupedExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + std::vector inner_attrs; + std::unique_ptr expr_in_parens; + Location locus; + +public: + std::string as_string () const override; + + const std::vector &get_inner_attrs () const { return inner_attrs; } + std::vector &get_inner_attrs () { return inner_attrs; } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + GroupedExpr (std::unique_ptr parenthesised_expr, + std::vector inner_attribs, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), + inner_attrs (std::move (inner_attribs)), + expr_in_parens (std::move (parenthesised_expr)), locus (locus) + {} + + // Copy constructor includes clone for expr_in_parens + GroupedExpr (GroupedExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + inner_attrs (other.inner_attrs), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.expr_in_parens != nullptr) + expr_in_parens = other.expr_in_parens->clone_expr (); + } + + // Overloaded assignment operator to clone expr_in_parens + GroupedExpr &operator= (GroupedExpr const &other) + { + ExprWithoutBlock::operator= (other); + inner_attrs = other.inner_attrs; + locus = other.locus; + outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.expr_in_parens != nullptr) + expr_in_parens = other.expr_in_parens->clone_expr (); + else + expr_in_parens = nullptr; + + return *this; + } + + // move constructors + GroupedExpr (GroupedExpr &&other) = default; + GroupedExpr &operator= (GroupedExpr &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if inner expr is null, so base stripping on that. + void mark_for_strip () override { expr_in_parens = nullptr; } + bool is_marked_for_strip () const override + { + return expr_in_parens == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_expr_in_parens () + { + rust_assert (expr_in_parens != nullptr); + return expr_in_parens; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + GroupedExpr *clone_expr_without_block_impl () const override + { + return new GroupedExpr (*this); + } +}; + +// Base array initialisation internal element representation thing (abstract) +// aka ArrayElements +class ArrayElems +{ +public: + virtual ~ArrayElems () {} + + // Unique pointer custom clone ArrayElems function + std::unique_ptr clone_array_elems () const + { + return std::unique_ptr (clone_array_elems_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + NodeId get_node_id () const { return node_id; } + +protected: + ArrayElems () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} + + // pure virtual clone implementation + virtual ArrayElems *clone_array_elems_impl () const = 0; + + NodeId node_id; +}; + +// Value array elements +class ArrayElemsValues : public ArrayElems +{ + std::vector > values; + Location locus; + +public: + ArrayElemsValues (std::vector > elems, Location locus) + : ArrayElems (), values (std::move (elems)), locus (locus) + {} + + // copy constructor with vector clone + ArrayElemsValues (ArrayElemsValues const &other) + { + values.reserve (other.values.size ()); + for (const auto &e : other.values) + values.push_back (e->clone_expr ()); + } + + // overloaded assignment operator with vector clone + ArrayElemsValues &operator= (ArrayElemsValues const &other) + { + values.reserve (other.values.size ()); + for (const auto &e : other.values) + values.push_back (e->clone_expr ()); + + return *this; + } + + // move constructors + ArrayElemsValues (ArrayElemsValues &&other) = default; + ArrayElemsValues &operator= (ArrayElemsValues &&other) = default; + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector > &get_values () const + { + return values; + } + std::vector > &get_values () { return values; } + + size_t get_num_values () const { return values.size (); } + +protected: + ArrayElemsValues *clone_array_elems_impl () const override + { + return new ArrayElemsValues (*this); + } +}; + +// Copied array element and number of copies +class ArrayElemsCopied : public ArrayElems +{ + std::unique_ptr elem_to_copy; + std::unique_ptr num_copies; + Location locus; + +public: + // Constructor requires pointers for polymorphism + ArrayElemsCopied (std::unique_ptr copied_elem, + std::unique_ptr copy_amount, Location locus) + : ArrayElems (), elem_to_copy (std::move (copied_elem)), + num_copies (std::move (copy_amount)), locus (locus) + {} + + // Copy constructor required due to unique_ptr - uses custom clone + ArrayElemsCopied (ArrayElemsCopied const &other) + : elem_to_copy (other.elem_to_copy->clone_expr ()), + num_copies (other.num_copies->clone_expr ()) + {} + + // Overloaded assignment operator for deep copying + ArrayElemsCopied &operator= (ArrayElemsCopied const &other) + { + elem_to_copy = other.elem_to_copy->clone_expr (); + num_copies = other.num_copies->clone_expr (); + + return *this; + } + + // move constructors + ArrayElemsCopied (ArrayElemsCopied &&other) = default; + ArrayElemsCopied &operator= (ArrayElemsCopied &&other) = default; + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_elem_to_copy () + { + rust_assert (elem_to_copy != nullptr); + return elem_to_copy; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_num_copies () + { + rust_assert (num_copies != nullptr); + return num_copies; + } + +protected: + ArrayElemsCopied *clone_array_elems_impl () const override + { + return new ArrayElemsCopied (*this); + } +}; + +// Array definition-ish expression +class ArrayExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + std::vector inner_attrs; + std::unique_ptr internal_elements; + Location locus; + + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + +public: + std::string as_string () const override; + + const std::vector &get_inner_attrs () const { return inner_attrs; } + std::vector &get_inner_attrs () { return inner_attrs; } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + // Constructor requires ArrayElems pointer + ArrayExpr (std::unique_ptr array_elems, + std::vector inner_attribs, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), + inner_attrs (std::move (inner_attribs)), + internal_elements (std::move (array_elems)), locus (locus) + { + rust_assert (internal_elements != nullptr); + } + + // Copy constructor requires cloning ArrayElems for polymorphism to hold + ArrayExpr (ArrayExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + inner_attrs (other.inner_attrs), locus (other.locus), + marked_for_strip (other.marked_for_strip) + { + internal_elements = other.internal_elements->clone_array_elems (); + rust_assert (internal_elements != nullptr); + } + + // Overload assignment operator to clone internal_elements + ArrayExpr &operator= (ArrayExpr const &other) + { + ExprWithoutBlock::operator= (other); + inner_attrs = other.inner_attrs; + locus = other.locus; + marked_for_strip = other.marked_for_strip; + outer_attrs = other.outer_attrs; + + internal_elements = other.internal_elements->clone_array_elems (); + + rust_assert (internal_elements != nullptr); + return *this; + } + + // move constructors + ArrayExpr (ArrayExpr &&other) = default; + ArrayExpr &operator= (ArrayExpr &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_array_elems () + { + rust_assert (internal_elements != nullptr); + return internal_elements; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ArrayExpr *clone_expr_without_block_impl () const override + { + return new ArrayExpr (*this); + } +}; + +// Aka IndexExpr (also applies to slices) +/* Apparently a[b] is equivalent to *std::ops::Index::index(&a, b) or + * *std::ops::Index::index_mut(&mut a, b) */ +/* Also apparently deref operations on a will be repeatedly applied to find an + * implementation */ +class ArrayIndexExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + std::unique_ptr array_expr; + std::unique_ptr index_expr; + Location locus; + +public: + std::string as_string () const override; + + ArrayIndexExpr (std::unique_ptr array_expr, + std::unique_ptr array_index_expr, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), + array_expr (std::move (array_expr)), + index_expr (std::move (array_index_expr)), locus (locus) + {} + + // Copy constructor requires special cloning due to unique_ptr + ArrayIndexExpr (ArrayIndexExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.array_expr != nullptr) + array_expr = other.array_expr->clone_expr (); + if (other.index_expr != nullptr) + index_expr = other.index_expr->clone_expr (); + } + + // Overload assignment operator to clone unique_ptrs + ArrayIndexExpr &operator= (ArrayIndexExpr const &other) + { + ExprWithoutBlock::operator= (other); + outer_attrs = other.outer_attrs; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.array_expr != nullptr) + array_expr = other.array_expr->clone_expr (); + else + array_expr = nullptr; + if (other.index_expr != nullptr) + index_expr = other.index_expr->clone_expr (); + else + index_expr = nullptr; + + return *this; + } + + // move constructors + ArrayIndexExpr (ArrayIndexExpr &&other) = default; + ArrayIndexExpr &operator= (ArrayIndexExpr &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if either expr is null, so base stripping on that. + void mark_for_strip () override + { + array_expr = nullptr; + index_expr = nullptr; + } + bool is_marked_for_strip () const override + { + return array_expr == nullptr && index_expr == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_array_expr () + { + rust_assert (array_expr != nullptr); + return array_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_index_expr () + { + rust_assert (index_expr != nullptr); + return index_expr; + } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ArrayIndexExpr *clone_expr_without_block_impl () const override + { + return new ArrayIndexExpr (*this); + } +}; + +// AST representation of a tuple +class TupleExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + std::vector inner_attrs; + std::vector > tuple_elems; + Location locus; + + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + +public: + std::string as_string () const override; + + const std::vector &get_inner_attrs () const { return inner_attrs; } + std::vector &get_inner_attrs () { return inner_attrs; } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + TupleExpr (std::vector > tuple_elements, + std::vector inner_attribs, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), + inner_attrs (std::move (inner_attribs)), + tuple_elems (std::move (tuple_elements)), locus (locus) + {} + + // copy constructor with vector clone + TupleExpr (TupleExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + inner_attrs (other.inner_attrs), locus (other.locus), + marked_for_strip (other.marked_for_strip) + { + tuple_elems.reserve (other.tuple_elems.size ()); + for (const auto &e : other.tuple_elems) + tuple_elems.push_back (e->clone_expr ()); + } + + // overloaded assignment operator to vector clone + TupleExpr &operator= (TupleExpr const &other) + { + ExprWithoutBlock::operator= (other); + outer_attrs = other.outer_attrs; + inner_attrs = other.inner_attrs; + locus = other.locus; + marked_for_strip = other.marked_for_strip; + + tuple_elems.reserve (other.tuple_elems.size ()); + for (const auto &e : other.tuple_elems) + tuple_elems.push_back (e->clone_expr ()); + + return *this; + } + + // move constructors + TupleExpr (TupleExpr &&other) = default; + TupleExpr &operator= (TupleExpr &&other) = default; + + /* Note: syntactically, can disambiguate single-element tuple from parens with + * comma, i.e. (0,) rather than (0) */ + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector > &get_tuple_elems () const + { + return tuple_elems; + } + std::vector > &get_tuple_elems () + { + return tuple_elems; + } + + bool is_unit () const { return tuple_elems.size () == 0; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + TupleExpr *clone_expr_without_block_impl () const override + { + return new TupleExpr (*this); + } +}; + +// aka TupleIndexingExpr +// AST representation of a tuple indexing expression +class TupleIndexExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + std::unique_ptr tuple_expr; + // TupleIndex is a decimal int literal with no underscores or suffix + TupleIndex tuple_index; + + Location locus; + + // i.e. pair.0 + +public: + std::string as_string () const override; + + TupleIndex get_tuple_index () const { return tuple_index; } + + TupleIndexExpr (std::unique_ptr tuple_expr, TupleIndex index, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), + tuple_expr (std::move (tuple_expr)), tuple_index (index), locus (locus) + {} + + // Copy constructor requires a clone for tuple_expr + TupleIndexExpr (TupleIndexExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + tuple_index (other.tuple_index), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.tuple_expr != nullptr) + tuple_expr = other.tuple_expr->clone_expr (); + } + + // Overload assignment operator in order to clone + TupleIndexExpr &operator= (TupleIndexExpr const &other) + { + ExprWithoutBlock::operator= (other); + tuple_index = other.tuple_index; + locus = other.locus; + outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.tuple_expr != nullptr) + tuple_expr = other.tuple_expr->clone_expr (); + else + tuple_expr = nullptr; + + return *this; + } + + // move constructors + TupleIndexExpr (TupleIndexExpr &&other) = default; + TupleIndexExpr &operator= (TupleIndexExpr &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if tuple expr is null, so base stripping on that. + void mark_for_strip () override { tuple_expr = nullptr; } + bool is_marked_for_strip () const override { return tuple_expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_tuple_expr () + { + rust_assert (tuple_expr != nullptr); + return tuple_expr; + } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + TupleIndexExpr *clone_expr_without_block_impl () const override + { + return new TupleIndexExpr (*this); + } +}; + +// Base struct/tuple/union value creator AST node (abstract) +class StructExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + PathInExpression struct_name; + +protected: + // Protected constructor to allow initialising struct_name + StructExpr (PathInExpression struct_path, + std::vector outer_attribs) + : outer_attrs (std::move (outer_attribs)), + struct_name (std::move (struct_path)) + {} + +public: + const PathInExpression &get_struct_name () const { return struct_name; } + PathInExpression &get_struct_name () { return struct_name; } + + std::string as_string () const override; + + // Invalid if path is empty, so base stripping on that. + void mark_for_strip () override + { + struct_name = PathInExpression::create_error (); + } + bool is_marked_for_strip () const override { return struct_name.is_error (); } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } +}; + +// Actual AST node of the struct creator (with no fields). Not abstract! +class StructExprStruct : public StructExpr +{ + std::vector inner_attrs; + + Location locus; + +public: + std::string as_string () const override; + + const std::vector &get_inner_attrs () const { return inner_attrs; } + std::vector &get_inner_attrs () { return inner_attrs; } + + // Constructor has to call protected constructor of base class + StructExprStruct (PathInExpression struct_path, + std::vector inner_attribs, + std::vector outer_attribs, Location locus) + : StructExpr (std::move (struct_path), std::move (outer_attribs)), + inner_attrs (std::move (inner_attribs)), locus (locus) + {} + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + StructExprStruct *clone_expr_without_block_impl () const override + { + return new StructExprStruct (*this); + } +}; + +/* AST node representing expression used to fill a struct's fields from another + * struct */ +struct StructBase +{ +private: + std::unique_ptr base_struct; + Location locus; + +public: + StructBase (std::unique_ptr base_struct_ptr, Location locus) + : base_struct (std::move (base_struct_ptr)), locus (locus) + {} + + // Copy constructor requires clone + StructBase (StructBase const &other) + { + /* HACK: gets around base_struct pointer being null (e.g. if no struct base + * exists) */ + if (other.base_struct != nullptr) + base_struct = other.base_struct->clone_expr (); + } + + // Destructor + ~StructBase () = default; + + // Overload assignment operator to clone base_struct + StructBase &operator= (StructBase const &other) + { + // prevent null pointer dereference + if (other.base_struct != nullptr) + base_struct = other.base_struct->clone_expr (); + else + base_struct = nullptr; + + return *this; + } + + // move constructors + StructBase (StructBase &&other) = default; + StructBase &operator= (StructBase &&other) = default; + + // Returns a null expr-ed StructBase - error state + static StructBase error () { return StructBase (nullptr, Location ()); } + + // Returns whether StructBase is in error state + bool is_invalid () const { return base_struct == nullptr; } + + std::string as_string () const; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_base_struct () + { + rust_assert (base_struct != nullptr); + return base_struct; + } +}; + +/* Base AST node for a single struct expression field (in struct instance + * creation) - abstract */ +class StructExprField +{ +public: + virtual ~StructExprField () {} + + // Unique pointer custom clone function + std::unique_ptr clone_struct_expr_field () const + { + return std::unique_ptr (clone_struct_expr_field_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual Location get_locus () const = 0; + + NodeId get_node_id () const { return node_id; } + +protected: + // pure virtual clone implementation + virtual StructExprField *clone_struct_expr_field_impl () const = 0; + + StructExprField () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + NodeId node_id; +}; + +// Identifier-only variant of StructExprField AST node +class StructExprFieldIdentifier : public StructExprField +{ + Identifier field_name; + Location locus; + +public: + StructExprFieldIdentifier (Identifier field_identifier, Location locus) + : StructExprField (), field_name (std::move (field_identifier)), + locus (locus) + {} + + std::string as_string () const override { return field_name; } + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + Identifier get_field_name () const { return field_name; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + StructExprFieldIdentifier *clone_struct_expr_field_impl () const override + { + return new StructExprFieldIdentifier (*this); + } +}; + +/* Base AST node for a single struct expression field with an assigned value - + * abstract */ +class StructExprFieldWithVal : public StructExprField +{ + std::unique_ptr value; + +protected: + StructExprFieldWithVal (std::unique_ptr field_value) + : StructExprField (), value (std::move (field_value)) + {} + + // Copy constructor requires clone + StructExprFieldWithVal (StructExprFieldWithVal const &other) + : value (other.value->clone_expr ()) + {} + + // Overload assignment operator to clone unique_ptr + StructExprFieldWithVal &operator= (StructExprFieldWithVal const &other) + { + value = other.value->clone_expr (); + + return *this; + } + + // move constructors + StructExprFieldWithVal (StructExprFieldWithVal &&other) = default; + StructExprFieldWithVal &operator= (StructExprFieldWithVal &&other) = default; + +public: + std::string as_string () const override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_value () + { + rust_assert (value != nullptr); + return value; + } +}; + +// Identifier and value variant of StructExprField AST node +class StructExprFieldIdentifierValue : public StructExprFieldWithVal +{ + Identifier field_name; + Location locus; + +public: + StructExprFieldIdentifierValue (Identifier field_identifier, + std::unique_ptr field_value, + Location locus) + : StructExprFieldWithVal (std::move (field_value)), + field_name (std::move (field_identifier)), locus (locus) + {} + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + std::string get_field_name () const { return field_name; } + + Location get_locus () const override final { return locus; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + StructExprFieldIdentifierValue *clone_struct_expr_field_impl () const override + { + return new StructExprFieldIdentifierValue (*this); + } +}; + +// Tuple index and value variant of StructExprField AST node +class StructExprFieldIndexValue : public StructExprFieldWithVal +{ + TupleIndex index; + Location locus; + +public: + StructExprFieldIndexValue (TupleIndex tuple_index, + std::unique_ptr field_value, Location locus) + : StructExprFieldWithVal (std::move (field_value)), index (tuple_index), + locus (locus) + {} + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + TupleIndex get_index () const { return index; } + + Location get_locus () const override final { return locus; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + StructExprFieldIndexValue *clone_struct_expr_field_impl () const override + { + return new StructExprFieldIndexValue (*this); + } +}; + +// AST node of a struct creator with fields +class StructExprStructFields : public StructExprStruct +{ + // std::vector fields; + std::vector > fields; + + // bool has_struct_base; + StructBase struct_base; + +public: + std::string as_string () const override; + + bool has_struct_base () const { return !struct_base.is_invalid (); } + + // Constructor for StructExprStructFields when no struct base is used + StructExprStructFields ( + PathInExpression struct_path, + std::vector > expr_fields, Location locus, + StructBase base_struct = StructBase::error (), + std::vector inner_attribs = std::vector (), + std::vector outer_attribs = std::vector ()) + : StructExprStruct (std::move (struct_path), std::move (inner_attribs), + std::move (outer_attribs), locus), + fields (std::move (expr_fields)), struct_base (std::move (base_struct)) + {} + + // copy constructor with vector clone + StructExprStructFields (StructExprStructFields const &other) + : StructExprStruct (other), struct_base (other.struct_base) + { + fields.reserve (other.fields.size ()); + for (const auto &e : other.fields) + fields.push_back (e->clone_struct_expr_field ()); + } + + // overloaded assignment operator with vector clone + StructExprStructFields &operator= (StructExprStructFields const &other) + { + StructExprStruct::operator= (other); + struct_base = other.struct_base; + + fields.reserve (other.fields.size ()); + for (const auto &e : other.fields) + fields.push_back (e->clone_struct_expr_field ()); + + return *this; + } + + // move constructors + StructExprStructFields (StructExprStructFields &&other) = default; + StructExprStructFields &operator= (StructExprStructFields &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector > &get_fields () + { + return fields; + } + const std::vector > &get_fields () const + { + return fields; + } + + StructBase &get_struct_base () { return struct_base; } + const StructBase &get_struct_base () const { return struct_base; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + StructExprStructFields *clone_expr_without_block_impl () const override + { + return new StructExprStructFields (*this); + } +}; + +// AST node of the functional update struct creator +/* TODO: remove and replace with StructExprStructFields, except with empty + * vector of fields? */ +class StructExprStructBase : public StructExprStruct +{ + StructBase struct_base; + +public: + std::string as_string () const override; + + StructExprStructBase (PathInExpression struct_path, StructBase base_struct, + std::vector inner_attribs, + std::vector outer_attribs, Location locus) + : StructExprStruct (std::move (struct_path), std::move (inner_attribs), + std::move (outer_attribs), locus), + struct_base (std::move (base_struct)) + {} + + void accept_vis (ASTVisitor &vis) override; + + StructBase &get_struct_base () { return struct_base; } + const StructBase &get_struct_base () const { return struct_base; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + StructExprStructBase *clone_expr_without_block_impl () const override + { + return new StructExprStructBase (*this); + } +}; + +// Forward decl for Function - used in CallExpr +class Function; + +// Function call expression AST node +class CallExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + std::unique_ptr function; + std::vector > params; + Location locus; + +public: + Function *fndeclRef; + + std::string as_string () const override; + + CallExpr (std::unique_ptr function_expr, + std::vector > function_params, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), + function (std::move (function_expr)), + params (std::move (function_params)), locus (locus) + {} + + // copy constructor requires clone + CallExpr (CallExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.function != nullptr) + function = other.function->clone_expr (); + + params.reserve (other.params.size ()); + for (const auto &e : other.params) + params.push_back (e->clone_expr ()); + } + + // Overload assignment operator to clone + CallExpr &operator= (CallExpr const &other) + { + ExprWithoutBlock::operator= (other); + locus = other.locus; + outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.function != nullptr) + function = other.function->clone_expr (); + else + function = nullptr; + + params.reserve (other.params.size ()); + for (const auto &e : other.params) + params.push_back (e->clone_expr ()); + + return *this; + } + + // move constructors + CallExpr (CallExpr &&other) = default; + CallExpr &operator= (CallExpr &&other) = default; + + // Returns whether function call has parameters. + bool has_params () const { return !params.empty (); } + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if function expr is null, so base stripping on that. + void mark_for_strip () override { function = nullptr; } + bool is_marked_for_strip () const override { return function == nullptr; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector > &get_params () const + { + return params; + } + std::vector > &get_params () { return params; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_function_expr () + { + rust_assert (function != nullptr); + return function; + } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + CallExpr *clone_expr_without_block_impl () const override + { + return new CallExpr (*this); + } +}; + +// Method call expression AST node +class MethodCallExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + std::unique_ptr receiver; + PathExprSegment method_name; + std::vector > params; + Location locus; + +public: + std::string as_string () const override; + + MethodCallExpr (std::unique_ptr call_receiver, + PathExprSegment method_path, + std::vector > method_params, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), + receiver (std::move (call_receiver)), + method_name (std::move (method_path)), params (std::move (method_params)), + locus (locus) + {} + + // copy constructor required due to cloning + MethodCallExpr (MethodCallExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + method_name (other.method_name), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.receiver != nullptr) + receiver = other.receiver->clone_expr (); + + params.reserve (other.params.size ()); + for (const auto &e : other.params) + params.push_back (e->clone_expr ()); + } + + // Overload assignment operator to clone receiver object + MethodCallExpr &operator= (MethodCallExpr const &other) + { + ExprWithoutBlock::operator= (other); + method_name = other.method_name; + locus = other.locus; + outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.receiver != nullptr) + receiver = other.receiver->clone_expr (); + else + receiver = nullptr; + + params.reserve (other.params.size ()); + for (const auto &e : other.params) + params.push_back (e->clone_expr ()); + + return *this; + } + + // move constructors + MethodCallExpr (MethodCallExpr &&other) = default; + MethodCallExpr &operator= (MethodCallExpr &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if receiver expr is null, so base stripping on that. + void mark_for_strip () override { receiver = nullptr; } + bool is_marked_for_strip () const override { return receiver == nullptr; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector > &get_params () const + { + return params; + } + std::vector > &get_params () { return params; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_receiver_expr () + { + rust_assert (receiver != nullptr); + return receiver; + } + + const PathExprSegment &get_method_name () const { return method_name; } + PathExprSegment &get_method_name () { return method_name; } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + MethodCallExpr *clone_expr_without_block_impl () const override + { + return new MethodCallExpr (*this); + } +}; + +// aka FieldExpression +// Struct or union field access expression AST node +class FieldAccessExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + std::unique_ptr receiver; + Identifier field; + Location locus; + +public: + std::string as_string () const override; + + FieldAccessExpr (std::unique_ptr field_access_receiver, + Identifier field_name, std::vector outer_attribs, + Location locus) + : outer_attrs (std::move (outer_attribs)), + receiver (std::move (field_access_receiver)), + field (std::move (field_name)), locus (locus) + {} + + // Copy constructor required due to unique_ptr cloning + FieldAccessExpr (FieldAccessExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + field (other.field), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.receiver != nullptr) + receiver = other.receiver->clone_expr (); + } + + // Overload assignment operator to clone unique_ptr + FieldAccessExpr &operator= (FieldAccessExpr const &other) + { + ExprWithoutBlock::operator= (other); + field = other.field; + locus = other.locus; + outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.receiver != nullptr) + receiver = other.receiver->clone_expr (); + else + receiver = nullptr; + + return *this; + } + + // move constructors + FieldAccessExpr (FieldAccessExpr &&other) = default; + FieldAccessExpr &operator= (FieldAccessExpr &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if receiver expr is null, so base stripping on that. + void mark_for_strip () override { receiver = nullptr; } + bool is_marked_for_strip () const override { return receiver == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_receiver_expr () + { + rust_assert (receiver != nullptr); + return receiver; + } + + Identifier get_field_name () const { return field; } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + FieldAccessExpr *clone_expr_without_block_impl () const override + { + return new FieldAccessExpr (*this); + } +}; + +// Closure parameter data structure +struct ClosureParam +{ +private: + std::vector outer_attrs; + std::unique_ptr pattern; + + // bool has_type_given; + std::unique_ptr type; + Location locus; + +public: + // Returns whether the type of the parameter has been given. + bool has_type_given () const { return type != nullptr; } + + bool has_outer_attrs () const { return !outer_attrs.empty (); } + + // Constructor for closure parameter + ClosureParam (std::unique_ptr param_pattern, Location locus, + std::unique_ptr param_type = nullptr, + std::vector outer_attrs = {}) + : outer_attrs (std::move (outer_attrs)), + pattern (std::move (param_pattern)), type (std::move (param_type)), + locus (locus) + {} + + // Copy constructor required due to cloning as a result of unique_ptrs + ClosureParam (ClosureParam const &other) : outer_attrs (other.outer_attrs) + { + // guard to protect from null pointer dereference + if (other.pattern != nullptr) + pattern = other.pattern->clone_pattern (); + if (other.type != nullptr) + type = other.type->clone_type (); + } + + ~ClosureParam () = default; + + // Assignment operator must be overloaded to clone as well + ClosureParam &operator= (ClosureParam const &other) + { + outer_attrs = other.outer_attrs; + + // guard to protect from null pointer dereference + if (other.pattern != nullptr) + pattern = other.pattern->clone_pattern (); + else + pattern = nullptr; + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + + return *this; + } + + // move constructors + ClosureParam (ClosureParam &&other) = default; + ClosureParam &operator= (ClosureParam &&other) = default; + + // Returns whether closure parameter is in an error state. + bool is_error () const { return pattern == nullptr; } + + // Creates an error state closure parameter. + static ClosureParam create_error () + { + return ClosureParam (nullptr, Location ()); + } + + std::string as_string () const; + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_pattern () + { + rust_assert (pattern != nullptr); + return pattern; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_type () + { + rust_assert (has_type_given ()); + return type; + } +}; + +// Base closure definition expression AST node - abstract +class ClosureExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + bool has_move; + std::vector params; // may be empty + Location locus; + +protected: + ClosureExpr (std::vector closure_params, bool has_move, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), has_move (has_move), + params (std::move (closure_params)), locus (locus) + {} + +public: + std::string as_string () const override; + + Location get_locus () const override final { return locus; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector &get_params () const { return params; } + std::vector &get_params () { return params; } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } +}; + +// Represents a non-type-specified closure expression AST node +class ClosureExprInner : public ClosureExpr +{ + std::unique_ptr closure_inner; + +public: + std::string as_string () const override; + + // Constructor for a ClosureExprInner + ClosureExprInner (std::unique_ptr closure_inner_expr, + std::vector closure_params, Location locus, + bool is_move = false, + std::vector outer_attribs + = std::vector ()) + : ClosureExpr (std::move (closure_params), is_move, + std::move (outer_attribs), locus), + closure_inner (std::move (closure_inner_expr)) + {} + + // Copy constructor must be defined to allow copying via cloning of unique_ptr + ClosureExprInner (ClosureExprInner const &other) : ClosureExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.closure_inner != nullptr) + closure_inner = other.closure_inner->clone_expr (); + } + + // Overload assignment operator to clone closure_inner + ClosureExprInner &operator= (ClosureExprInner const &other) + { + ClosureExpr::operator= (other); + // params = other.params; + // has_move = other.has_move; + // outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.closure_inner != nullptr) + closure_inner = other.closure_inner->clone_expr (); + else + closure_inner = nullptr; + + return *this; + } + + // move constructors + ClosureExprInner (ClosureExprInner &&other) = default; + ClosureExprInner &operator= (ClosureExprInner &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if inner expr is null, so base stripping on that. + void mark_for_strip () override { closure_inner = nullptr; } + bool is_marked_for_strip () const override + { + return closure_inner == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_definition_expr () + { + rust_assert (closure_inner != nullptr); + return closure_inner; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ClosureExprInner *clone_expr_without_block_impl () const override + { + return new ClosureExprInner (*this); + } +}; + +// A block AST node +class BlockExpr : public ExprWithBlock +{ + std::vector outer_attrs; + std::vector inner_attrs; + std::vector > statements; + std::unique_ptr expr; + Location start_locus; + Location end_locus; + bool marked_for_strip = false; + +public: + std::string as_string () const override; + + // Returns whether the block contains statements. + bool has_statements () const { return !statements.empty (); } + + // Returns whether the block contains a final expression. + bool has_tail_expr () const { return expr != nullptr; } + + BlockExpr (std::vector > block_statements, + std::unique_ptr block_expr, + std::vector inner_attribs, + std::vector outer_attribs, Location start_locus, + Location end_locus) + : outer_attrs (std::move (outer_attribs)), + inner_attrs (std::move (inner_attribs)), + statements (std::move (block_statements)), expr (std::move (block_expr)), + start_locus (start_locus), end_locus (end_locus) + {} + + // Copy constructor with clone + BlockExpr (BlockExpr const &other) + : ExprWithBlock (other), outer_attrs (other.outer_attrs), + inner_attrs (other.inner_attrs), start_locus (other.start_locus), + end_locus (other.end_locus), marked_for_strip (other.marked_for_strip) + { + // guard to protect from null pointer dereference + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + + statements.reserve (other.statements.size ()); + for (const auto &e : other.statements) + statements.push_back (e->clone_stmt ()); + } + + // Overloaded assignment operator to clone pointer + BlockExpr &operator= (BlockExpr const &other) + { + ExprWithBlock::operator= (other); + inner_attrs = other.inner_attrs; + start_locus = other.start_locus; + end_locus = other.end_locus; + marked_for_strip = other.marked_for_strip; + outer_attrs = other.outer_attrs; + + // guard to protect from null pointer dereference + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + else + expr = nullptr; + + statements.reserve (other.statements.size ()); + for (const auto &e : other.statements) + statements.push_back (e->clone_stmt ()); + + return *this; + } + + // move constructors + BlockExpr (BlockExpr &&other) = default; + BlockExpr &operator= (BlockExpr &&other) = default; + + // Unique pointer custom clone function + std::unique_ptr clone_block_expr () const + { + return std::unique_ptr (clone_block_expr_impl ()); + } + + Location get_locus () const override final { return start_locus; } + + Location get_start_locus () const { return start_locus; } + Location get_end_locus () const { return end_locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Can be completely empty, so have to have a separate flag. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + size_t num_statements () const { return statements.size (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector &get_inner_attrs () const { return inner_attrs; } + std::vector &get_inner_attrs () { return inner_attrs; } + + const std::vector > &get_statements () const + { + return statements; + } + std::vector > &get_statements () { return statements; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_tail_expr () + { + rust_assert (has_tail_expr ()); + return expr; + } + + // Removes the tail expression from the block. + void strip_tail_expr () { expr = nullptr; } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + BlockExpr *clone_expr_with_block_impl () const final override + { + return clone_block_expr_impl (); + } + + /* This is the base method as not an abstract class - not virtual but could be + * in future if required. */ + /*virtual*/ BlockExpr *clone_block_expr_impl () const + { + return new BlockExpr (*this); + } +}; + +// Represents a type-specified closure expression AST node +class ClosureExprInnerTyped : public ClosureExpr +{ + // TODO: spec says typenobounds + std::unique_ptr return_type; + std::unique_ptr + expr; // only used because may be polymorphic in future + +public: + std::string as_string () const override; + + // Constructor potentially with a move + ClosureExprInnerTyped (std::unique_ptr closure_return_type, + std::unique_ptr closure_expr, + std::vector closure_params, + Location locus, bool is_move = false, + std::vector outer_attribs + = std::vector ()) + : ClosureExpr (std::move (closure_params), is_move, + std::move (outer_attribs), locus), + return_type (std::move (closure_return_type)), + expr (std::move (closure_expr)) + {} + + // Copy constructor requires cloning + ClosureExprInnerTyped (ClosureExprInnerTyped const &other) + : ClosureExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_block_expr (); + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + } + + // Overload assignment operator to clone unique_ptrs + ClosureExprInnerTyped &operator= (ClosureExprInnerTyped const &other) + { + ClosureExpr::operator= (other); + // params = other.params; + // has_move = other.has_move; + // outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_block_expr (); + else + expr = nullptr; + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + + return *this; + } + + // move constructors + ClosureExprInnerTyped (ClosureExprInnerTyped &&other) = default; + ClosureExprInnerTyped &operator= (ClosureExprInnerTyped &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + /* Invalid if inner expr is null, so base stripping on that. Technically, + * type should also not be null. */ + void mark_for_strip () override { expr = nullptr; } + bool is_marked_for_strip () const override { return expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_definition_block () + { + rust_assert (expr != nullptr); + return expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_return_type () + { + rust_assert (return_type != nullptr); + return return_type; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ClosureExprInnerTyped *clone_expr_without_block_impl () const override + { + return new ClosureExprInnerTyped (*this); + } +}; + +// AST node representing continue expression within loops +class ContinueExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + Lifetime label; + Location locus; + + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + +public: + std::string as_string () const override; + + // Returns true if the continue expr has a label. + bool has_label () const { return !label.is_error (); } + + // Constructor for a ContinueExpr with a label. + ContinueExpr (Lifetime label, std::vector outer_attribs, + Location locus) + : outer_attrs (std::move (outer_attribs)), label (std::move (label)), + locus (locus) + {} + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + Lifetime &get_label () { return label; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ContinueExpr *clone_expr_without_block_impl () const override + { + return new ContinueExpr (*this); + } +}; +// TODO: merge "break" and "continue"? Or even merge in "return"? + +// AST node representing break expression within loops +class BreakExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + Lifetime label; + std::unique_ptr break_expr; + Location locus; + + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + +public: + std::string as_string () const override; + + // Returns whether the break expression has a label or not. + bool has_label () const { return !label.is_error (); } + + /* Returns whether the break expression has an expression used in the break or + * not. */ + bool has_break_expr () const { return break_expr != nullptr; } + + // Constructor for a break expression + BreakExpr (Lifetime break_label, std::unique_ptr expr_in_break, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), label (std::move (break_label)), + break_expr (std::move (expr_in_break)), locus (locus) + {} + + // Copy constructor defined to use clone for unique pointer + BreakExpr (BreakExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + label (other.label), locus (other.locus), + marked_for_strip (other.marked_for_strip) + { + // guard to protect from null pointer dereference + if (other.break_expr != nullptr) + break_expr = other.break_expr->clone_expr (); + } + + // Overload assignment operator to clone unique pointer + BreakExpr &operator= (BreakExpr const &other) + { + ExprWithoutBlock::operator= (other); + label = other.label; + locus = other.locus; + marked_for_strip = other.marked_for_strip; + outer_attrs = other.outer_attrs; + + // guard to protect from null pointer dereference + if (other.break_expr != nullptr) + break_expr = other.break_expr->clone_expr (); + else + break_expr = nullptr; + + return *this; + } + + // move constructors + BreakExpr (BreakExpr &&other) = default; + BreakExpr &operator= (BreakExpr &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_break_expr () + { + rust_assert (has_break_expr ()); + return break_expr; + } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + Lifetime &get_label () { return label; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + BreakExpr *clone_expr_without_block_impl () const override + { + return new BreakExpr (*this); + } +}; + +// Base range expression AST node object - abstract +class RangeExpr : public ExprWithoutBlock +{ + Location locus; + +protected: + // outer attributes not allowed before range expressions + RangeExpr (Location locus) : locus (locus) {} + +public: + Location get_locus () const override final { return locus; } + + // should never be called - error if called + void set_outer_attrs (std::vector /* new_attrs */) override + { + rust_assert (false); + } +}; + +// Range from (inclusive) and to (exclusive) expression AST node object +// aka RangeExpr; constructs a std::ops::Range object +class RangeFromToExpr : public RangeExpr +{ + std::unique_ptr from; + std::unique_ptr to; + +public: + std::string as_string () const override; + + RangeFromToExpr (std::unique_ptr range_from, + std::unique_ptr range_to, Location locus) + : RangeExpr (locus), from (std::move (range_from)), + to (std::move (range_to)) + {} + + // Copy constructor with cloning + RangeFromToExpr (RangeFromToExpr const &other) : RangeExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + if (other.to != nullptr) + to = other.to->clone_expr (); + } + + // Overload assignment operator to clone unique pointers + RangeFromToExpr &operator= (RangeFromToExpr const &other) + { + RangeExpr::operator= (other); + + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + else + from = nullptr; + if (other.to != nullptr) + to = other.to->clone_expr (); + else + to = nullptr; + + return *this; + } + + // move constructors + RangeFromToExpr (RangeFromToExpr &&other) = default; + RangeFromToExpr &operator= (RangeFromToExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if either expr is null, so base stripping on that. + void mark_for_strip () override + { + from = nullptr; + to = nullptr; + } + bool is_marked_for_strip () const override + { + return from == nullptr && to == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_from_expr () + { + rust_assert (from != nullptr); + return from; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_to_expr () + { + rust_assert (to != nullptr); + return to; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + RangeFromToExpr *clone_expr_without_block_impl () const override + { + return new RangeFromToExpr (*this); + } +}; + +// Range from (inclusive) expression AST node object +// constructs a std::ops::RangeFrom object +class RangeFromExpr : public RangeExpr +{ + std::unique_ptr from; + +public: + std::string as_string () const override; + + RangeFromExpr (std::unique_ptr range_from, Location locus) + : RangeExpr (locus), from (std::move (range_from)) + {} + + // Copy constructor with clone + RangeFromExpr (RangeFromExpr const &other) : RangeExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + } + + // Overload assignment operator to clone unique_ptr + RangeFromExpr &operator= (RangeFromExpr const &other) + { + RangeExpr::operator= (other); + + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + else + from = nullptr; + + return *this; + } + + // move constructors + RangeFromExpr (RangeFromExpr &&other) = default; + RangeFromExpr &operator= (RangeFromExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if expr is null, so base stripping on that. + void mark_for_strip () override { from = nullptr; } + bool is_marked_for_strip () const override { return from == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_from_expr () + { + rust_assert (from != nullptr); + return from; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + RangeFromExpr *clone_expr_without_block_impl () const override + { + return new RangeFromExpr (*this); + } +}; + +// Range to (exclusive) expression AST node object +// constructs a std::ops::RangeTo object +class RangeToExpr : public RangeExpr +{ + std::unique_ptr to; + +public: + std::string as_string () const override; + + // outer attributes not allowed + RangeToExpr (std::unique_ptr range_to, Location locus) + : RangeExpr (locus), to (std::move (range_to)) + {} + + // Copy constructor with clone + RangeToExpr (RangeToExpr const &other) : RangeExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.to != nullptr) + to = other.to->clone_expr (); + } + + // Overload assignment operator to clone unique_ptr + RangeToExpr &operator= (RangeToExpr const &other) + { + RangeExpr::operator= (other); + + // guard to prevent null dereference (only required if error state) + if (other.to != nullptr) + to = other.to->clone_expr (); + else + to = nullptr; + + return *this; + } + + // move constructors + RangeToExpr (RangeToExpr &&other) = default; + RangeToExpr &operator= (RangeToExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if expr is null, so base stripping on that. + void mark_for_strip () override { to = nullptr; } + bool is_marked_for_strip () const override { return to == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_to_expr () + { + rust_assert (to != nullptr); + return to; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + RangeToExpr *clone_expr_without_block_impl () const override + { + return new RangeToExpr (*this); + } +}; + +// Full range expression AST node object +// constructs a std::ops::RangeFull object +class RangeFullExpr : public RangeExpr +{ + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + +public: + std::string as_string () const override; + + RangeFullExpr (Location locus) : RangeExpr (locus) {} + // outer attributes not allowed + + void accept_vis (ASTVisitor &vis) override; + + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + RangeFullExpr *clone_expr_without_block_impl () const override + { + return new RangeFullExpr (*this); + } +}; + +// Range from (inclusive) and to (inclusive) expression AST node object +// aka RangeInclusiveExpr; constructs a std::ops::RangeInclusive object +class RangeFromToInclExpr : public RangeExpr +{ + std::unique_ptr from; + std::unique_ptr to; + +public: + std::string as_string () const override; + + RangeFromToInclExpr (std::unique_ptr range_from, + std::unique_ptr range_to, Location locus) + : RangeExpr (locus), from (std::move (range_from)), + to (std::move (range_to)) + {} + // outer attributes not allowed + + // Copy constructor with clone + RangeFromToInclExpr (RangeFromToInclExpr const &other) : RangeExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + if (other.to != nullptr) + to = other.to->clone_expr (); + } + + // Overload assignment operator to use clone + RangeFromToInclExpr &operator= (RangeFromToInclExpr const &other) + { + RangeExpr::operator= (other); + + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + else + from = nullptr; + if (other.to != nullptr) + to = other.to->clone_expr (); + else + to = nullptr; + + return *this; + } + + // move constructors + RangeFromToInclExpr (RangeFromToInclExpr &&other) = default; + RangeFromToInclExpr &operator= (RangeFromToInclExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if either expr is null, so base stripping on that. + void mark_for_strip () override + { + from = nullptr; + to = nullptr; + } + bool is_marked_for_strip () const override + { + return from == nullptr && to == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_from_expr () + { + rust_assert (from != nullptr); + return from; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_to_expr () + { + rust_assert (to != nullptr); + return to; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + RangeFromToInclExpr *clone_expr_without_block_impl () const override + { + return new RangeFromToInclExpr (*this); + } +}; + +// Range to (inclusive) expression AST node object +// aka RangeToInclusiveExpr; constructs a std::ops::RangeToInclusive object +class RangeToInclExpr : public RangeExpr +{ + std::unique_ptr to; + +public: + std::string as_string () const override; + + RangeToInclExpr (std::unique_ptr range_to, Location locus) + : RangeExpr (locus), to (std::move (range_to)) + {} + // outer attributes not allowed + + // Copy constructor with clone + RangeToInclExpr (RangeToInclExpr const &other) : RangeExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.to != nullptr) + to = other.to->clone_expr (); + } + + // Overload assignment operator to clone pointer + RangeToInclExpr &operator= (RangeToInclExpr const &other) + { + RangeExpr::operator= (other); + + // guard to prevent null dereference (only required if error state) + if (other.to != nullptr) + to = other.to->clone_expr (); + else + to = nullptr; + + return *this; + } + + // move constructors + RangeToInclExpr (RangeToInclExpr &&other) = default; + RangeToInclExpr &operator= (RangeToInclExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if expr is null, so base stripping on that. + void mark_for_strip () override { to = nullptr; } + bool is_marked_for_strip () const override { return to == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_to_expr () + { + rust_assert (to != nullptr); + return to; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + RangeToInclExpr *clone_expr_without_block_impl () const override + { + return new RangeToInclExpr (*this); + } +}; + +// Return expression AST node representation +class ReturnExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + std::unique_ptr return_expr; + Location locus; + + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + +public: + std::string as_string () const override; + + /* Returns whether the object has an expression returned (i.e. not void return + * type). */ + bool has_returned_expr () const { return return_expr != nullptr; } + + // Constructor for ReturnExpr. + ReturnExpr (std::unique_ptr returned_expr, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), + return_expr (std::move (returned_expr)), locus (locus) + {} + + // Copy constructor with clone + ReturnExpr (ReturnExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + locus (other.locus), marked_for_strip (other.marked_for_strip) + { + // guard to protect from null pointer dereference + if (other.return_expr != nullptr) + return_expr = other.return_expr->clone_expr (); + } + + // Overloaded assignment operator to clone return_expr pointer + ReturnExpr &operator= (ReturnExpr const &other) + { + ExprWithoutBlock::operator= (other); + locus = other.locus; + marked_for_strip = other.marked_for_strip; + outer_attrs = other.outer_attrs; + + // guard to protect from null pointer dereference + if (other.return_expr != nullptr) + return_expr = other.return_expr->clone_expr (); + else + return_expr = nullptr; + + return *this; + } + + // move constructors + ReturnExpr (ReturnExpr &&other) = default; + ReturnExpr &operator= (ReturnExpr &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_returned_expr () + { + rust_assert (return_expr != nullptr); + return return_expr; + } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ReturnExpr *clone_expr_without_block_impl () const override + { + return new ReturnExpr (*this); + } +}; + +// Forward decl - defined in rust-macro.h +class MacroInvocation; + +// An unsafe block AST node +class UnsafeBlockExpr : public ExprWithBlock +{ + std::vector outer_attrs; + // Or just have it extend BlockExpr + std::unique_ptr expr; + Location locus; + +public: + std::string as_string () const override; + + UnsafeBlockExpr (std::unique_ptr block_expr, + std::vector outer_attribs, Location locus) + : outer_attrs (std::move (outer_attribs)), expr (std::move (block_expr)), + locus (locus) + {} + + // Copy constructor with clone + UnsafeBlockExpr (UnsafeBlockExpr const &other) + : ExprWithBlock (other), outer_attrs (other.outer_attrs), + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_block_expr (); + } + + // Overloaded assignment operator to clone + UnsafeBlockExpr &operator= (UnsafeBlockExpr const &other) + { + ExprWithBlock::operator= (other); + locus = other.locus; + outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_block_expr (); + else + expr = nullptr; + + return *this; + } + + // move constructors + UnsafeBlockExpr (UnsafeBlockExpr &&other) = default; + UnsafeBlockExpr &operator= (UnsafeBlockExpr &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if block is null, so base stripping on that. + void mark_for_strip () override { expr = nullptr; } + bool is_marked_for_strip () const override { return expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_block_expr () + { + rust_assert (expr != nullptr); + return expr; + } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + UnsafeBlockExpr *clone_expr_with_block_impl () const override + { + return new UnsafeBlockExpr (*this); + } +}; + +// Loop label expression AST node used with break and continue expressions +// TODO: inline? +class LoopLabel /*: public Node*/ +{ + Lifetime label; // or type LIFETIME_OR_LABEL + Location locus; + + NodeId node_id; + +public: + std::string as_string () const; + + LoopLabel (Lifetime loop_label, Location locus = Location ()) + : label (std::move (loop_label)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + // Returns whether the LoopLabel is in an error state. + bool is_error () const { return label.is_error (); } + + // Creates an error state LoopLabel. + static LoopLabel error () { return LoopLabel (Lifetime::error ()); } + + Location get_locus () const { return locus; } + + Lifetime &get_lifetime () { return label; } + + NodeId get_node_id () const { return node_id; } +}; + +// Base loop expression AST node - aka LoopExpr +class BaseLoopExpr : public ExprWithBlock +{ +protected: + // protected to allow subclasses better use of them + std::vector outer_attrs; + LoopLabel loop_label; + std::unique_ptr loop_block; + +private: + Location locus; + +protected: + // Constructor for BaseLoopExpr + BaseLoopExpr (std::unique_ptr loop_block, Location locus, + LoopLabel loop_label = LoopLabel::error (), + std::vector outer_attribs + = std::vector ()) + : outer_attrs (std::move (outer_attribs)), + loop_label (std::move (loop_label)), loop_block (std::move (loop_block)), + locus (locus) + {} + + // Copy constructor for BaseLoopExpr with clone + BaseLoopExpr (BaseLoopExpr const &other) + : ExprWithBlock (other), outer_attrs (other.outer_attrs), + loop_label (other.loop_label), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.loop_block != nullptr) + loop_block = other.loop_block->clone_block_expr (); + } + + // Overloaded assignment operator to clone + BaseLoopExpr &operator= (BaseLoopExpr const &other) + { + ExprWithBlock::operator= (other); + loop_label = other.loop_label; + locus = other.locus; + outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.loop_block != nullptr) + loop_block = other.loop_block->clone_block_expr (); + else + loop_block = nullptr; + + return *this; + } + + // move constructors + BaseLoopExpr (BaseLoopExpr &&other) = default; + BaseLoopExpr &operator= (BaseLoopExpr &&other) = default; + +public: + bool has_loop_label () const { return !loop_label.is_error (); } + + LoopLabel &get_loop_label () { return loop_label; } + + Location get_locus () const override final { return locus; } + + // Invalid if loop block is null, so base stripping on that. + void mark_for_strip () override { loop_block = nullptr; } + bool is_marked_for_strip () const override { return loop_block == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_loop_block () + { + rust_assert (loop_block != nullptr); + return loop_block; + } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } +}; + +// 'Loop' expression (i.e. the infinite loop) AST node +class LoopExpr : public BaseLoopExpr +{ +public: + std::string as_string () const override; + + // Constructor for LoopExpr + LoopExpr (std::unique_ptr loop_block, Location locus, + LoopLabel loop_label = LoopLabel::error (), + std::vector outer_attribs = std::vector ()) + : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label), + std::move (outer_attribs)) + {} + + void accept_vis (ASTVisitor &vis) override; + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + LoopExpr *clone_expr_with_block_impl () const override + { + return new LoopExpr (*this); + } +}; + +// While loop expression AST node (predicate loop) +class WhileLoopExpr : public BaseLoopExpr +{ + std::unique_ptr condition; + +public: + std::string as_string () const override; + + // Constructor for while loop with loop label + WhileLoopExpr (std::unique_ptr loop_condition, + std::unique_ptr loop_block, Location locus, + LoopLabel loop_label = LoopLabel::error (), + std::vector outer_attribs + = std::vector ()) + : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label), + std::move (outer_attribs)), + condition (std::move (loop_condition)) + {} + + // Copy constructor with clone + WhileLoopExpr (WhileLoopExpr const &other) + : BaseLoopExpr (other), condition (other.condition->clone_expr ()) + {} + + // Overloaded assignment operator to clone + WhileLoopExpr &operator= (WhileLoopExpr const &other) + { + BaseLoopExpr::operator= (other); + condition = other.condition->clone_expr (); + // loop_block = other.loop_block->clone_block_expr(); + // loop_label = other.loop_label; + // outer_attrs = other.outer_attrs; + + return *this; + } + + // move constructors + WhileLoopExpr (WhileLoopExpr &&other) = default; + WhileLoopExpr &operator= (WhileLoopExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_predicate_expr () + { + rust_assert (condition != nullptr); + return condition; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + WhileLoopExpr *clone_expr_with_block_impl () const override + { + return new WhileLoopExpr (*this); + } +}; + +// While let loop expression AST node (predicate pattern loop) +class WhileLetLoopExpr : public BaseLoopExpr +{ + // MatchArmPatterns patterns; + std::vector > match_arm_patterns; // inlined + std::unique_ptr scrutinee; + +public: + std::string as_string () const override; + + // Constructor with a loop label + WhileLetLoopExpr (std::vector > match_arm_patterns, + std::unique_ptr scrutinee, + std::unique_ptr loop_block, Location locus, + LoopLabel loop_label = LoopLabel::error (), + std::vector outer_attribs + = std::vector ()) + : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label), + std::move (outer_attribs)), + match_arm_patterns (std::move (match_arm_patterns)), + scrutinee (std::move (scrutinee)) + {} + + // Copy constructor with clone + WhileLetLoopExpr (WhileLetLoopExpr const &other) + : BaseLoopExpr (other), + /*match_arm_patterns(other.match_arm_patterns),*/ scrutinee ( + other.scrutinee->clone_expr ()) + { + match_arm_patterns.reserve (other.match_arm_patterns.size ()); + for (const auto &e : other.match_arm_patterns) + match_arm_patterns.push_back (e->clone_pattern ()); + } + + // Overloaded assignment operator to clone pointers + WhileLetLoopExpr &operator= (WhileLetLoopExpr const &other) + { + BaseLoopExpr::operator= (other); + // match_arm_patterns = other.match_arm_patterns; + scrutinee = other.scrutinee->clone_expr (); + // loop_block = other.loop_block->clone_block_expr(); + // loop_label = other.loop_label; + // outer_attrs = other.outer_attrs; + + match_arm_patterns.reserve (other.match_arm_patterns.size ()); + for (const auto &e : other.match_arm_patterns) + match_arm_patterns.push_back (e->clone_pattern ()); + + return *this; + } + + // move constructors + WhileLetLoopExpr (WhileLetLoopExpr &&other) = default; + WhileLetLoopExpr &operator= (WhileLetLoopExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_scrutinee_expr () + { + rust_assert (scrutinee != nullptr); + return scrutinee; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector > &get_patterns () const + { + return match_arm_patterns; + } + std::vector > &get_patterns () + { + return match_arm_patterns; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + WhileLetLoopExpr *clone_expr_with_block_impl () const override + { + return new WhileLetLoopExpr (*this); + } +}; + +// For loop expression AST node (iterator loop) +class ForLoopExpr : public BaseLoopExpr +{ + std::unique_ptr pattern; + std::unique_ptr iterator_expr; + +public: + std::string as_string () const override; + + // Constructor with loop label + ForLoopExpr (std::unique_ptr loop_pattern, + std::unique_ptr iterator_expr, + std::unique_ptr loop_body, Location locus, + LoopLabel loop_label = LoopLabel::error (), + std::vector outer_attribs = std::vector ()) + : BaseLoopExpr (std::move (loop_body), locus, std::move (loop_label), + std::move (outer_attribs)), + pattern (std::move (loop_pattern)), + iterator_expr (std::move (iterator_expr)) + {} + + // Copy constructor with clone + ForLoopExpr (ForLoopExpr const &other) + : BaseLoopExpr (other), pattern (other.pattern->clone_pattern ()), + iterator_expr (other.iterator_expr->clone_expr ()) + {} + + // Overloaded assignment operator to clone + ForLoopExpr &operator= (ForLoopExpr const &other) + { + BaseLoopExpr::operator= (other); + pattern = other.pattern->clone_pattern (); + iterator_expr = other.iterator_expr->clone_expr (); + /*loop_block = other.loop_block->clone_block_expr(); + loop_label = other.loop_label; + outer_attrs = other.outer_attrs;*/ + + return *this; + } + + // move constructors + ForLoopExpr (ForLoopExpr &&other) = default; + ForLoopExpr &operator= (ForLoopExpr &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_iterator_expr () + { + rust_assert (iterator_expr != nullptr); + return iterator_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_pattern () + { + rust_assert (pattern != nullptr); + return pattern; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ForLoopExpr *clone_expr_with_block_impl () const override + { + return new ForLoopExpr (*this); + } +}; + +// forward decl for IfExpr +class IfLetExpr; + +// Base if expression with no "else" or "if let" AST node +class IfExpr : public ExprWithBlock +{ + std::vector outer_attrs; + std::unique_ptr condition; + std::unique_ptr if_block; + Location locus; + +public: + std::string as_string () const override; + + IfExpr (std::unique_ptr condition, std::unique_ptr if_block, + std::vector outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), condition (std::move (condition)), + if_block (std::move (if_block)), locus (locus) + {} + // outer attributes are never allowed on IfExprs + + // Copy constructor with clone + IfExpr (IfExpr const &other) + : ExprWithBlock (other), outer_attrs (other.outer_attrs), + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.condition != nullptr) + condition = other.condition->clone_expr (); + if (other.if_block != nullptr) + if_block = other.if_block->clone_block_expr (); + } + + // Overloaded assignment operator to clone expressions + IfExpr &operator= (IfExpr const &other) + { + ExprWithBlock::operator= (other); + outer_attrs = other.outer_attrs; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.condition != nullptr) + condition = other.condition->clone_expr (); + else + condition = nullptr; + if (other.if_block != nullptr) + if_block = other.if_block->clone_block_expr (); + else + if_block = nullptr; + + return *this; + } + + // move constructors + IfExpr (IfExpr &&other) = default; + IfExpr &operator= (IfExpr &&other) = default; + + // Unique pointer custom clone function + std::unique_ptr clone_if_expr () const + { + return std::unique_ptr (clone_if_expr_impl ()); + } + + /* Note that multiple "else if"s are handled via nested ASTs rather than a + * vector of else ifs - i.e. not like a switch statement. TODO - is this a + * better approach? or does it not parse correctly and have downsides? */ + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + void vis_if_condition (ASTVisitor &vis) { condition->accept_vis (vis); } + void vis_if_block (ASTVisitor &vis) { if_block->accept_vis (vis); } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_condition_expr () + { + rust_assert (condition != nullptr); + return condition; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_if_block () + { + rust_assert (if_block != nullptr); + return if_block; + } + + // Invalid if if block or condition is null, so base stripping on that. + void mark_for_strip () override + { + if_block = nullptr; + condition = nullptr; + } + bool is_marked_for_strip () const override + { + return if_block == nullptr && condition == nullptr; + } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + +protected: + // Base clone function but still concrete as concrete base class + virtual IfExpr *clone_if_expr_impl () const { return new IfExpr (*this); } + + /* Use covariance to implement clone function as returning this object rather + * than base */ + IfExpr *clone_expr_with_block_impl () const final override + { + return clone_if_expr_impl (); + } +}; + +// If expression with an ending "else" expression AST node (trailing) +class IfExprConseqElse : public IfExpr +{ + std::unique_ptr else_block; + +public: + std::string as_string () const override; + + IfExprConseqElse (std::unique_ptr condition, + std::unique_ptr if_block, + std::unique_ptr else_block, + std::vector outer_attrs, Location locus) + : IfExpr (std::move (condition), std::move (if_block), + std::move (outer_attrs), locus), + else_block (std::move (else_block)) + {} + // again, outer attributes not allowed + + // Copy constructor with clone + IfExprConseqElse (IfExprConseqElse const &other) + : IfExpr (other), else_block (other.else_block->clone_block_expr ()) + {} + + // Overloaded assignment operator with cloning + IfExprConseqElse &operator= (IfExprConseqElse const &other) + { + IfExpr::operator= (other); + // condition = other.condition->clone_expr(); + // if_block = other.if_block->clone_block_expr(); + else_block = other.else_block->clone_block_expr (); + + return *this; + } + + // move constructors + IfExprConseqElse (IfExprConseqElse &&other) = default; + IfExprConseqElse &operator= (IfExprConseqElse &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + void vis_else_block (ASTVisitor &vis) { else_block->accept_vis (vis); } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_else_block () + { + rust_assert (else_block != nullptr); + return else_block; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + IfExprConseqElse *clone_if_expr_impl () const override + { + return new IfExprConseqElse (*this); + } +}; + +// If expression with an ending "else if" expression AST node +class IfExprConseqIf : public IfExpr +{ + std::unique_ptr conseq_if_expr; + +public: + std::string as_string () const override; + + IfExprConseqIf (std::unique_ptr condition, + std::unique_ptr if_block, + std::unique_ptr conseq_if_expr, + std::vector outer_attrs, Location locus) + : IfExpr (std::move (condition), std::move (if_block), + std::move (outer_attrs), locus), + conseq_if_expr (std::move (conseq_if_expr)) + {} + // outer attributes not allowed + + // Copy constructor with clone + IfExprConseqIf (IfExprConseqIf const &other) + : IfExpr (other), conseq_if_expr (other.conseq_if_expr->clone_if_expr ()) + {} + + // Overloaded assignment operator to use clone + IfExprConseqIf &operator= (IfExprConseqIf const &other) + { + IfExpr::operator= (other); + // condition = other.condition->clone_expr(); + // if_block = other.if_block->clone_block_expr(); + conseq_if_expr = other.conseq_if_expr->clone_if_expr (); + + return *this; + } + + // move constructors + IfExprConseqIf (IfExprConseqIf &&other) = default; + IfExprConseqIf &operator= (IfExprConseqIf &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + void vis_conseq_if_expr (ASTVisitor &vis) + { + conseq_if_expr->accept_vis (vis); + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_conseq_if_expr () + { + rust_assert (conseq_if_expr != nullptr); + return conseq_if_expr; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + IfExprConseqIf *clone_if_expr_impl () const override + { + return new IfExprConseqIf (*this); + } +}; + +// Basic "if let" expression AST node with no else +class IfLetExpr : public ExprWithBlock +{ + std::vector outer_attrs; + std::vector > match_arm_patterns; // inlined + std::unique_ptr value; + std::unique_ptr if_block; + Location locus; + +public: + std::string as_string () const override; + + IfLetExpr (std::vector > match_arm_patterns, + std::unique_ptr value, std::unique_ptr if_block, + std::vector outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), + match_arm_patterns (std::move (match_arm_patterns)), + value (std::move (value)), if_block (std::move (if_block)), locus (locus) + {} + + // copy constructor with clone + IfLetExpr (IfLetExpr const &other) + : ExprWithBlock (other), outer_attrs (other.outer_attrs), + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.value != nullptr) + value = other.value->clone_expr (); + if (other.if_block != nullptr) + if_block = other.if_block->clone_block_expr (); + + match_arm_patterns.reserve (other.match_arm_patterns.size ()); + for (const auto &e : other.match_arm_patterns) + match_arm_patterns.push_back (e->clone_pattern ()); + } + + // overload assignment operator to clone + IfLetExpr &operator= (IfLetExpr const &other) + { + ExprWithBlock::operator= (other); + outer_attrs = other.outer_attrs; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.value != nullptr) + value = other.value->clone_expr (); + else + value = nullptr; + if (other.if_block != nullptr) + if_block = other.if_block->clone_block_expr (); + else + if_block = nullptr; + + match_arm_patterns.reserve (other.match_arm_patterns.size ()); + for (const auto &e : other.match_arm_patterns) + match_arm_patterns.push_back (e->clone_pattern ()); + + return *this; + } + + // move constructors + IfLetExpr (IfLetExpr &&other) = default; + IfLetExpr &operator= (IfLetExpr &&other) = default; + + // Unique pointer custom clone function + std::unique_ptr clone_if_let_expr () const + { + return std::unique_ptr (clone_if_let_expr_impl ()); + } + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if block or value is null, so base stripping on that. + void mark_for_strip () override + { + if_block = nullptr; + value = nullptr; + } + bool is_marked_for_strip () const override + { + return if_block == nullptr && value == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_value_expr () + { + rust_assert (value != nullptr); + return value; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_if_block () + { + rust_assert (if_block != nullptr); + return if_block; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector > &get_patterns () const + { + return match_arm_patterns; + } + std::vector > &get_patterns () + { + return match_arm_patterns; + } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base (or rather this or any derived object) */ + IfLetExpr *clone_expr_with_block_impl () const final override + { + return clone_if_let_expr_impl (); + } + + // Base clone function but still concrete as concrete base class + virtual IfLetExpr *clone_if_let_expr_impl () const + { + return new IfLetExpr (*this); + } +}; + +// If expression with an ending "else if let" expression AST node +class IfExprConseqIfLet : public IfExpr +{ + std::unique_ptr if_let_expr; + +public: + std::string as_string () const override; + + IfExprConseqIfLet (std::unique_ptr condition, + std::unique_ptr if_block, + std::unique_ptr conseq_if_let_expr, + std::vector outer_attrs, Location locus) + : IfExpr (std::move (condition), std::move (if_block), + std::move (outer_attrs), locus), + if_let_expr (std::move (conseq_if_let_expr)) + {} + // outer attributes not allowed + + // Copy constructor with clone + IfExprConseqIfLet (IfExprConseqIfLet const &other) + : IfExpr (other), if_let_expr (other.if_let_expr->clone_if_let_expr ()) + {} + + // Overloaded assignment operator to use clone + IfExprConseqIfLet &operator= (IfExprConseqIfLet const &other) + { + IfExpr::operator= (other); + // condition = other.condition->clone_expr(); + // if_block = other.if_block->clone_block_expr(); + if_let_expr = other.if_let_expr->clone_if_let_expr (); + + return *this; + } + + // move constructors + IfExprConseqIfLet (IfExprConseqIfLet &&other) = default; + IfExprConseqIfLet &operator= (IfExprConseqIfLet &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_conseq_if_let_expr () + { + rust_assert (if_let_expr != nullptr); + return if_let_expr; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + IfExprConseqIfLet *clone_if_expr_impl () const override + { + return new IfExprConseqIfLet (*this); + } +}; + +/* AST node representing "if let" expression with an "else" expression at the + * end */ +class IfLetExprConseqElse : public IfLetExpr +{ + std::unique_ptr else_block; + +public: + std::string as_string () const override; + + IfLetExprConseqElse ( + std::vector > match_arm_patterns, + std::unique_ptr value, std::unique_ptr if_block, + std::unique_ptr else_block, std::vector outer_attrs, + Location locus) + : IfLetExpr (std::move (match_arm_patterns), std::move (value), + std::move (if_block), std::move (outer_attrs), locus), + else_block (std::move (else_block)) + {} + // outer attributes not allowed + + // copy constructor with clone + IfLetExprConseqElse (IfLetExprConseqElse const &other) + : IfLetExpr (other), else_block (other.else_block->clone_block_expr ()) + {} + + // overload assignment operator to clone + IfLetExprConseqElse &operator= (IfLetExprConseqElse const &other) + { + IfLetExpr::operator= (other); + // match_arm_patterns = other.match_arm_patterns; + // value = other.value->clone_expr(); + // if_block = other.if_block->clone_block_expr(); + else_block = other.else_block->clone_block_expr (); + // outer_attrs = other.outer_attrs; + + return *this; + } + + // move constructors + IfLetExprConseqElse (IfLetExprConseqElse &&other) = default; + IfLetExprConseqElse &operator= (IfLetExprConseqElse &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_else_block () + { + rust_assert (else_block != nullptr); + return else_block; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + IfLetExprConseqElse *clone_if_let_expr_impl () const override + { + return new IfLetExprConseqElse (*this); + } +}; + +/* AST node representing "if let" expression with an "else if" expression at the + * end */ +class IfLetExprConseqIf : public IfLetExpr +{ + std::unique_ptr if_expr; + +public: + std::string as_string () const override; + + IfLetExprConseqIf (std::vector > match_arm_patterns, + std::unique_ptr value, + std::unique_ptr if_block, + std::unique_ptr if_expr, + std::vector outer_attrs, Location locus) + : IfLetExpr (std::move (match_arm_patterns), std::move (value), + std::move (if_block), std::move (outer_attrs), locus), + if_expr (std::move (if_expr)) + {} + // again, outer attributes not allowed + + // copy constructor with clone + IfLetExprConseqIf (IfLetExprConseqIf const &other) + : IfLetExpr (other), if_expr (other.if_expr->clone_if_expr ()) + {} + + // overload assignment operator to clone + IfLetExprConseqIf &operator= (IfLetExprConseqIf const &other) + { + IfLetExpr::operator= (other); + // match_arm_patterns = other.match_arm_patterns; + // value = other.value->clone_expr(); + // if_block = other.if_block->clone_block_expr(); + if_expr = other.if_expr->clone_if_expr (); + + return *this; + } + + // move constructors + IfLetExprConseqIf (IfLetExprConseqIf &&other) = default; + IfLetExprConseqIf &operator= (IfLetExprConseqIf &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_conseq_if_expr () + { + rust_assert (if_expr != nullptr); + return if_expr; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + IfLetExprConseqIf *clone_if_let_expr_impl () const override + { + return new IfLetExprConseqIf (*this); + } +}; + +/* AST node representing "if let" expression with an "else if let" expression at + * the end */ +class IfLetExprConseqIfLet : public IfLetExpr +{ + std::unique_ptr if_let_expr; + +public: + std::string as_string () const override; + + IfLetExprConseqIfLet ( + std::vector > match_arm_patterns, + std::unique_ptr value, std::unique_ptr if_block, + std::unique_ptr if_let_expr, std::vector outer_attrs, + Location locus) + : IfLetExpr (std::move (match_arm_patterns), std::move (value), + std::move (if_block), std::move (outer_attrs), locus), + if_let_expr (std::move (if_let_expr)) + {} + // outer attributes not allowed + + // copy constructor with clone + IfLetExprConseqIfLet (IfLetExprConseqIfLet const &other) + : IfLetExpr (other), if_let_expr (other.if_let_expr->clone_if_let_expr ()) + {} + + // overload assignment operator to clone + IfLetExprConseqIfLet &operator= (IfLetExprConseqIfLet const &other) + { + IfLetExpr::operator= (other); + // match_arm_patterns = other.match_arm_patterns; + // value = other.value->clone_expr(); + // if_block = other.if_block->clone_block_expr(); + if_let_expr = other.if_let_expr->clone_if_let_expr (); + + return *this; + } + + // move constructors + IfLetExprConseqIfLet (IfLetExprConseqIfLet &&other) = default; + IfLetExprConseqIfLet &operator= (IfLetExprConseqIfLet &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_conseq_if_let_expr () + { + rust_assert (if_let_expr != nullptr); + return if_let_expr; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + IfLetExprConseqIfLet *clone_if_let_expr_impl () const override + { + return new IfLetExprConseqIfLet (*this); + } +}; + +// Match arm expression +struct MatchArm +{ +private: + std::vector outer_attrs; + // MatchArmPatterns patterns; + std::vector > match_arm_patterns; // inlined + + // bool has_match_arm_guard; + // inlined from MatchArmGuard + std::unique_ptr guard_expr; + + Location locus; + +public: + // Returns whether the MatchArm has a match arm guard expression + bool has_match_arm_guard () const { return guard_expr != nullptr; } + + // Constructor for match arm with a guard expression + MatchArm (std::vector > match_arm_patterns, + Location locus, std::unique_ptr guard_expr = nullptr, + std::vector outer_attrs = std::vector ()) + : outer_attrs (std::move (outer_attrs)), + match_arm_patterns (std::move (match_arm_patterns)), + guard_expr (std::move (guard_expr)), locus (locus) + {} + + // Copy constructor with clone + MatchArm (MatchArm const &other) : outer_attrs (other.outer_attrs) + { + // guard to protect from null pointer dereference + if (other.guard_expr != nullptr) + guard_expr = other.guard_expr->clone_expr (); + + match_arm_patterns.reserve (other.match_arm_patterns.size ()); + for (const auto &e : other.match_arm_patterns) + match_arm_patterns.push_back (e->clone_pattern ()); + + locus = other.locus; + } + + ~MatchArm () = default; + + // Overload assignment operator to clone + MatchArm &operator= (MatchArm const &other) + { + outer_attrs = other.outer_attrs; + + if (other.guard_expr != nullptr) + guard_expr = other.guard_expr->clone_expr (); + else + guard_expr = nullptr; + + match_arm_patterns.reserve (other.match_arm_patterns.size ()); + for (const auto &e : other.match_arm_patterns) + match_arm_patterns.push_back (e->clone_pattern ()); + + return *this; + } + + // move constructors + MatchArm (MatchArm &&other) = default; + MatchArm &operator= (MatchArm &&other) = default; + + // Returns whether match arm is in an error state. + bool is_error () const { return match_arm_patterns.empty (); } + + // Creates a match arm in an error state. + static MatchArm create_error () + { + Location locus = Location (); + return MatchArm (std::vector > (), locus); + } + + std::string as_string () const; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_guard_expr () + { + rust_assert (has_match_arm_guard ()); + return guard_expr; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + const std::vector > &get_patterns () const + { + return match_arm_patterns; + } + std::vector > &get_patterns () + { + return match_arm_patterns; + } + + Location get_locus () const { return locus; } +}; + +/* A "match case" - a correlated match arm and resulting expression. Not + * abstract. */ +struct MatchCase +{ +private: + MatchArm arm; + std::unique_ptr expr; + NodeId node_id; + + /* TODO: does whether trailing comma exists need to be stored? currently + * assuming it is only syntactical and has no effect on meaning. */ + +public: + MatchCase (MatchArm arm, std::unique_ptr expr) + : arm (std::move (arm)), expr (std::move (expr)), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + MatchCase (const MatchCase &other) + : arm (other.arm), expr (other.expr->clone_expr ()), node_id (other.node_id) + {} + + MatchCase &operator= (const MatchCase &other) + { + arm = other.arm; + expr = other.expr->clone_expr (); + node_id = other.node_id; + + return *this; + } + + MatchCase (MatchCase &&other) = default; + MatchCase &operator= (MatchCase &&other) = default; + + ~MatchCase () = default; + + std::string as_string () const; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_expr () + { + rust_assert (expr != nullptr); + return expr; + } + + // TODO: is this better? Or is a "vis_block" better? + MatchArm &get_arm () + { + rust_assert (!arm.is_error ()); + return arm; + } + + NodeId get_node_id () const { return node_id; } +}; + +// Match expression AST node +class MatchExpr : public ExprWithBlock +{ + std::vector outer_attrs; + std::unique_ptr branch_value; + std::vector inner_attrs; + std::vector match_arms; + Location locus; + +public: + std::string as_string () const override; + + // Returns whether the match expression has any match arms. + bool has_match_arms () const { return !match_arms.empty (); } + + MatchExpr (std::unique_ptr branch_value, + std::vector match_arms, + std::vector inner_attrs, + std::vector outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), + branch_value (std::move (branch_value)), + inner_attrs (std::move (inner_attrs)), + match_arms (std::move (match_arms)), locus (locus) + {} + + // Copy constructor requires clone due to unique_ptr + MatchExpr (MatchExpr const &other) + : ExprWithBlock (other), outer_attrs (other.outer_attrs), + inner_attrs (other.inner_attrs), match_arms (other.match_arms), + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.branch_value != nullptr) + branch_value = other.branch_value->clone_expr (); + } + + // Overloaded assignment operator to clone due to unique_ptr + MatchExpr &operator= (MatchExpr const &other) + { + ExprWithBlock::operator= (other); + inner_attrs = other.inner_attrs; + match_arms = other.match_arms; + outer_attrs = other.outer_attrs; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.branch_value != nullptr) + branch_value = other.branch_value->clone_expr (); + else + branch_value = nullptr; + + return *this; + } + + // move constructors + MatchExpr (MatchExpr &&other) = default; + MatchExpr &operator= (MatchExpr &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if branch value is null, so base stripping on that. + void mark_for_strip () override { branch_value = nullptr; } + bool is_marked_for_strip () const override { return branch_value == nullptr; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector &get_inner_attrs () const { return inner_attrs; } + std::vector &get_inner_attrs () { return inner_attrs; } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_scrutinee_expr () + { + rust_assert (branch_value != nullptr); + return branch_value; + } + + const std::vector &get_match_cases () const { return match_arms; } + std::vector &get_match_cases () { return match_arms; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + MatchExpr *clone_expr_with_block_impl () const override + { + return new MatchExpr (*this); + } +}; + +// Await expression AST node (pseudo-member variable access) +class AwaitExpr : public ExprWithoutBlock +{ + std::vector outer_attrs; + std::unique_ptr awaited_expr; + Location locus; + +public: + // TODO: ensure outer attributes are actually allowed + AwaitExpr (std::unique_ptr awaited_expr, + std::vector outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), + awaited_expr (std::move (awaited_expr)), locus (locus) + {} + + // copy constructor with clone + AwaitExpr (AwaitExpr const &other) + : ExprWithoutBlock (other), outer_attrs (other.outer_attrs), + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.awaited_expr != nullptr) + awaited_expr = other.awaited_expr->clone_expr (); + } + + // overloaded assignment operator with clone + AwaitExpr &operator= (AwaitExpr const &other) + { + ExprWithoutBlock::operator= (other); + outer_attrs = other.outer_attrs; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.awaited_expr != nullptr) + awaited_expr = other.awaited_expr->clone_expr (); + else + awaited_expr = nullptr; + + return *this; + } + + // move constructors + AwaitExpr (AwaitExpr &&other) = default; + AwaitExpr &operator= (AwaitExpr &&other) = default; + + std::string as_string () const override; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if awaited expr is null, so base stripping on that. + void mark_for_strip () override { awaited_expr = nullptr; } + bool is_marked_for_strip () const override { return awaited_expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_awaited_expr () + { + rust_assert (awaited_expr != nullptr); + return awaited_expr; + } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + AwaitExpr *clone_expr_without_block_impl () const override + { + return new AwaitExpr (*this); + } +}; + +// Async block expression AST node (block expr that evaluates to a future) +class AsyncBlockExpr : public ExprWithBlock +{ + // TODO: should this extend BlockExpr rather than be a composite of it? + std::vector outer_attrs; + bool has_move; + std::unique_ptr block_expr; + Location locus; + +public: + AsyncBlockExpr (std::unique_ptr block_expr, bool has_move, + std::vector outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), has_move (has_move), + block_expr (std::move (block_expr)), locus (locus) + {} + + // copy constructor with clone + AsyncBlockExpr (AsyncBlockExpr const &other) + : ExprWithBlock (other), outer_attrs (other.outer_attrs), + has_move (other.has_move), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + } + + // overloaded assignment operator to clone + AsyncBlockExpr &operator= (AsyncBlockExpr const &other) + { + ExprWithBlock::operator= (other); + outer_attrs = other.outer_attrs; + has_move = other.has_move; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + else + block_expr = nullptr; + + return *this; + } + + // move constructors + AsyncBlockExpr (AsyncBlockExpr &&other) = default; + AsyncBlockExpr &operator= (AsyncBlockExpr &&other) = default; + + std::string as_string () const override; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Invalid if block is null, so base stripping on that. + void mark_for_strip () override { block_expr = nullptr; } + bool is_marked_for_strip () const override { return block_expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr &get_block_expr () + { + rust_assert (block_expr != nullptr); + return block_expr; + } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + AsyncBlockExpr *clone_expr_with_block_impl () const override + { + return new AsyncBlockExpr (*this); + } +}; +} // namespace AST +} // namespace Rust + +#endif diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h new file mode 100644 index 00000000000..147037501ff --- /dev/null +++ b/gcc/rust/ast/rust-macro.h @@ -0,0 +1,958 @@ +// Copyright (C) 2020-2022 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 +// . + +#ifndef RUST_AST_MACRO_H +#define RUST_AST_MACRO_H + +#include "rust-system.h" +#include "rust-ast.h" +#include "rust-location.h" + +namespace Rust { +namespace AST { + +// Decls as definitions moved to rust-ast.h +class MacroItem; + +class MacroFragSpec +{ +public: + enum Kind + { + BLOCK, + EXPR, + IDENT, + ITEM, + LIFETIME, + LITERAL, + META, + PAT, + PATH, + STMT, + TT, + TY, + VIS, + INVALID // not really a specifier, but used to mark invalid one passed in + }; + + MacroFragSpec (Kind kind) : kind (kind) {} + + static MacroFragSpec get_frag_spec_from_str (const std::string &str) + { + if (str == "block") + return MacroFragSpec (BLOCK); + else if (str == "expr") + return MacroFragSpec (EXPR); + else if (str == "ident") + return MacroFragSpec (IDENT); + else if (str == "item") + return MacroFragSpec (ITEM); + else if (str == "lifetime") + return MacroFragSpec (LIFETIME); + else if (str == "literal") + return MacroFragSpec (LITERAL); + else if (str == "meta") + return MacroFragSpec (META); + else if (str == "pat" || str == "pat_param") + return MacroFragSpec (PAT); + else if (str == "path") + return MacroFragSpec (PATH); + else if (str == "stmt") + return MacroFragSpec (STMT); + else if (str == "tt") + return MacroFragSpec (TT); + else if (str == "ty") + return MacroFragSpec (TY); + else if (str == "vis") + return MacroFragSpec (VIS); + else + { + // error_at("invalid string '%s' used as fragment specifier", + // str->c_str())); + return MacroFragSpec (INVALID); + } + } + + Kind get_kind () const { return kind; } + bool is_error () const { return kind == Kind::INVALID; } + + // Converts a frag spec enum item to a string form. + std::string as_string () const + { + switch (kind) + { + case BLOCK: + return "block"; + case EXPR: + return "expr"; + case IDENT: + return "ident"; + case ITEM: + return "item"; + case LIFETIME: + return "lifetime"; + case LITERAL: + return "literal"; + case META: + return "meta"; + case PAT: + return "pat"; + case PATH: + return "path"; + case STMT: + return "stmt"; + case TT: + return "tt"; + case TY: + return "ty"; + case VIS: + return "vis"; + case INVALID: + return "INVALID_FRAG_SPEC"; + default: + return "ERROR_MARK_STRING - unknown frag spec"; + } + } + + bool has_follow_set_restrictions () const + { + switch (kind) + { + case EXPR: + case STMT: + case PAT: + case PATH: + case TY: + case VIS: + return true; + default: + return false; + } + } + + bool has_follow_set_fragment_restrictions () const + { + switch (kind) + { + case PAT: + case TY: + case VIS: + return true; + default: + return false; + } + } + +private: + Kind kind; +}; + +// A macro match that has an identifier and fragment spec +class MacroMatchFragment : public MacroMatch +{ + Identifier ident; + MacroFragSpec frag_spec; + Location locus; + +public: + MacroMatchFragment (Identifier ident, MacroFragSpec frag_spec, Location locus) + : ident (std::move (ident)), frag_spec (frag_spec), locus (locus) + {} + + // Returns whether macro match fragment is in an error state. + bool is_error () const + { + return frag_spec.get_kind () == MacroFragSpec::INVALID; + } + + // Creates an error state macro match fragment. + static MacroMatchFragment create_error (Location locus) + { + return MacroMatchFragment (std::string (""), + MacroFragSpec (MacroFragSpec::Kind::INVALID), + locus); + } + + std::string as_string () const override; + Location get_match_locus () const override { return locus; }; + + void accept_vis (ASTVisitor &vis) override; + + MacroMatchType get_macro_match_type () const override + { + return MacroMatchType::Fragment; + } + + Identifier get_ident () const { return ident; } + const MacroFragSpec &get_frag_spec () const { return frag_spec; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + MacroMatchFragment *clone_macro_match_impl () const override + { + return new MacroMatchFragment (*this); + } +}; + +// A repetition macro match +class MacroMatchRepetition : public MacroMatch +{ +public: + enum MacroRepOp + { + NONE, + ANY, + ONE_OR_MORE, + ZERO_OR_ONE, + }; + +private: + std::vector > matches; + MacroRepOp op; + + // bool has_sep; + typedef Token MacroRepSep; + // any token except delimiters and repetition operators + std::unique_ptr sep; + Location locus; + +public: + // Returns whether macro match repetition has separator token. + bool has_sep () const { return sep != nullptr; } + + MacroMatchRepetition (std::vector > matches, + MacroRepOp op, std::unique_ptr sep, + Location locus) + : matches (std::move (matches)), op (op), sep (std::move (sep)), + locus (locus) + {} + + // Copy constructor with clone + MacroMatchRepetition (MacroMatchRepetition const &other) + : op (other.op), locus (other.locus) + { + // guard to protect from null pointer dereference + if (other.sep != nullptr) + sep = other.sep->clone_token (); + + matches.reserve (other.matches.size ()); + for (const auto &e : other.matches) + matches.push_back (e->clone_macro_match ()); + } + + // Overloaded assignment operator to clone + MacroMatchRepetition &operator= (MacroMatchRepetition const &other) + { + op = other.op; + locus = other.locus; + + // guard to protect from null pointer dereference + if (other.sep != nullptr) + sep = other.sep->clone_token (); + else + sep = nullptr; + + matches.reserve (other.matches.size ()); + for (const auto &e : other.matches) + matches.push_back (e->clone_macro_match ()); + + return *this; + } + + // move constructors + MacroMatchRepetition (MacroMatchRepetition &&other) = default; + MacroMatchRepetition &operator= (MacroMatchRepetition &&other) = default; + + std::string as_string () const override; + Location get_match_locus () const override { return locus; }; + + void accept_vis (ASTVisitor &vis) override; + + MacroMatchType get_macro_match_type () const override + { + return MacroMatchType::Repetition; + } + + MacroRepOp get_op () const { return op; } + const std::unique_ptr &get_sep () const { return sep; } + std::vector > &get_matches () { return matches; } + const std::vector > &get_matches () const + { + return matches; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + MacroMatchRepetition *clone_macro_match_impl () const override + { + return new MacroMatchRepetition (*this); + } +}; + +// can't inline due to polymorphism +class MacroMatcher : public MacroMatch +{ + DelimType delim_type; + std::vector > matches; + Location locus; + + // TODO: think